]> git.proxmox.com Git - ceph.git/blame - 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
CommitLineData
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
12Up until now, the most basic ingredient is missing: creation of and access to
13local variables in the stack. When recursion comes into play, you will soon
14realize the need to have true local variables. It may seem that we do not need
15this at all since an unnamed lambda function cannot call itself anyway; at least
16not directly. With some sort of arrangement, situations will arise where a
17lambda function becomes recursive. A typical situation occurs when we store a
18lambda function in a [@http://www.boost.org/libs/function Boost.Function],
19essentially naming the unnamed lambda.
20
21There will also be situations where a lambda function gets passed as an argument
22to another function. This is a more common situation. In this case, the lambda
23function assumes a new scope; new arguments and possibly new local variables.
24
25This section deals with local variables and nested lambda scopes.
26
27[section Local Variables]
28
29 #include <boost/phoenix/scope/local_variable.hpp>
30
31We use an instance of:
32
33 expression::local_variable<Key>::type
34
35to represent a local variable. The local variable acts as an imaginary data-bin
36where a local, stack based data will be placed. `Key` is an arbitrary type that
37is 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
44There are a few predefined instances of `expression::local_variable<Key>::type`
45named `_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
55You 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
68variable declarations in a let expression. By default, `BOOST_PHOENIX_LOCAL_LIMIT` is
69set to `BOOST_PHOENIX_LIMIT`.]
70
71Example:
72
73 let(_a = 123, _b = 456)
74 [
75 _a + _b
76 ]
77
78[*Reference Preservation]
79
80The type of the local variable assumes the type of the lambda- expression. Type
81deduction 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
88Consider this:
89
90 int i = 1;
91
92 let(_a = arg1)
93 [
94 cout << --_a << ' '
95 ]
96 (i);
97
98 cout << i << endl;
99
100the output of above is : 0 0
101
102While 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
114the output is : 0 1
115
116Reference preservation is necessary because we need to have L-value access to
117outer 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
123The 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.
125For 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
137The actual values of the parameters _1, _2 and _3 are supplied from the
138bracketed list at the end of the `let`.
139
140There is currently a limitation that the inner `let` cannot be supplied with a
141constant e.g. `let(_x = 1)`.
142
143The RHS (right hand side lambda-expression) of each local-declaration cannot
144refer to any LHS local-id. At this point, the local-ids are not in scope yet;
145they 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
156However, if an outer let scope is available, this will be searched. Since
157the scope of the RHS of a local-declaration is the outer scope enclosing
158the let, the RHS of a local-declaration can refer to a local variable of
159an 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
177A lot of times, you'd want to write a lazy function that accepts one or more
178functions (higher order functions). STL algorithms come to mind, for example.
179Consider 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
198Notice that the function accepts another function, `f` as an argument. The scope
199of this function, `f`, is limited within the `operator()`. When `f` is called
200inside `std::for_each`, it exists in a new scope, along with new arguments and,
201possibly, local variables. This new scope is not at all related to the outer
202scopes beyond the `operator()`.
203
204Simple syntax:
205
206 lambda
207 [
208 lambda-body
209 ]
210
211Like `let`, local variables may be declared, allowing 1..N local variable
212declarations (where N == `BOOST_PHOENIX_LOCAL_LIMIT`):
213
214 lambda(local-declarations)
215 [
216 lambda-body
217 ]
218
219The same restrictions apply with regard to scope and visibility. The RHS
220(right hand side lambda-expression) of each local-declaration cannot refer
221to any LHS local-id. The local-ids are not in scope yet; they will be in
222scope only in the lambda-body:
223
224 lambda(
225 _a = 1
226 , _b = _a // Error: _a is not in scope yet
227 )
228
229See [link phoenix.modules.scope.let.visibility `let` Visibility] for more information.
230
231Example: Using our lazy `for_each` let's print all the elements in a container:
232
233 for_each(arg1, lambda[cout << arg1])
234
235As far as the arguments are concerned (arg1..argN), the scope in which the
236lambda-body exists is totally new. The left `arg1` refers to the argument passed
237to `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`
239above (a container element).
240
241Yet, we may wish to get information from outer scopes. While we do not have
242access to arguments in outer scopes, what we still have is access to local
243variables from outer scopes. We may only be able to pass argument related
244information from outer `lambda` scopes through the local variables.
245
246[note This is a crucial difference between `let` and `lambda`: `let`
247does not introduce new arguments; `lambda` does.]
248
249Another 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
268write a lambda expression that accepts:
269
270# a 2-dimensional container (e.g. `vector<vector<int> >`)
271# a container element (e.g. `int`)
272
273and pushes-back the element to each of the `vector<int>`.
274
275Solution:
276
277 for_each(arg1,
278 lambda(_a = arg2)
279 [
280 push_back(arg1, _a)
281 ]
282 )
283
284Since we do not have access to the arguments of the outer scopes beyond the
285lambda-body, we introduce a local variable `_a` that captures the second outer
286argument: `arg2`. Hence: _a = arg2. This local variable is visible inside the
287lambda scope.
288
289(See [@../../example/lambda.cpp lambda.cpp])
290
291[endsect]
292
293[endsect]