294 lines
8.3 KiB
Plaintext
294 lines
8.3 KiB
Plaintext
[/==============================================================================
|
|
Copyright (C) 2001-2010 Joel de Guzman
|
|
Copyright (C) 2001-2005 Dan Marsden
|
|
Copyright (C) 2001-2010 Thomas Heller
|
|
|
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
===============================================================================/]
|
|
|
|
[section Scope]
|
|
|
|
Up until now, the most basic ingredient is missing: creation of and access to
|
|
local variables in the stack. When recursion comes into play, you will soon
|
|
realize the need to have true local variables. It may seem that we do not need
|
|
this at all since an unnamed lambda function cannot call itself anyway; at least
|
|
not directly. With some sort of arrangement, situations will arise where a
|
|
lambda function becomes recursive. A typical situation occurs when we store a
|
|
lambda function in a [@http://www.boost.org/libs/function Boost.Function],
|
|
essentially naming the unnamed lambda.
|
|
|
|
There will also be situations where a lambda function gets passed as an argument
|
|
to another function. This is a more common situation. In this case, the lambda
|
|
function assumes a new scope; new arguments and possibly new local variables.
|
|
|
|
This section deals with local variables and nested lambda scopes.
|
|
|
|
[section Local Variables]
|
|
|
|
#include <boost/phoenix/scope/local_variable.hpp>
|
|
|
|
We use an instance of:
|
|
|
|
expression::local_variable<Key>::type
|
|
|
|
to represent a local variable. The local variable acts as an imaginary data-bin
|
|
where a local, stack based data will be placed. `Key` is an arbitrary type that
|
|
is used to identify the local variable. Example:
|
|
|
|
struct size_key;
|
|
expression::local_variable<size_key>::type size;
|
|
|
|
[*Predefined Local Variables]
|
|
|
|
There are a few predefined instances of `expression::local_variable<Key>::type`
|
|
named `_a`..`_z` that you can already use. To make use of them, simply use the
|
|
`namespace boost::phoenix::local_names`:
|
|
|
|
using namespace boost::phoenix::local_names;
|
|
|
|
[endsect]
|
|
[section let]
|
|
|
|
#include <boost/phoenix/scope/let.hpp>
|
|
|
|
You declare local variables using the syntax:
|
|
|
|
let(local-declarations)
|
|
[
|
|
let-body
|
|
]
|
|
|
|
`let` allows 1..N local variable declarations (where N ==
|
|
`BOOST_PHOENIX_LOCAL_LIMIT`). Each declaration follows the form:
|
|
|
|
local-id = lambda-expression
|
|
|
|
[note You can set `BOOST_PHOENIX_LOCAL_LIMIT`, the predefined maximum local
|
|
variable declarations in a let expression. By default, `BOOST_PHOENIX_LOCAL_LIMIT` is
|
|
set to `BOOST_PHOENIX_LIMIT`.]
|
|
|
|
Example:
|
|
|
|
let(_a = 123, _b = 456)
|
|
[
|
|
_a + _b
|
|
]
|
|
|
|
[*Reference Preservation]
|
|
|
|
The type of the local variable assumes the type of the lambda- expression. Type
|
|
deduction is reference preserving. For example:
|
|
|
|
let(_a = arg1, _b = 456)
|
|
|
|
`_a` assumes the type of `arg1`: a reference to an argument, while `_b` has type
|
|
`int`.
|
|
|
|
Consider this:
|
|
|
|
int i = 1;
|
|
|
|
let(_a = arg1)
|
|
[
|
|
cout << --_a << ' '
|
|
]
|
|
(i);
|
|
|
|
cout << i << endl;
|
|
|
|
the output of above is : 0 0
|
|
|
|
While with this:
|
|
|
|
int i = 1;
|
|
|
|
let(_a = val(arg1))
|
|
[
|
|
cout << --_a << ' '
|
|
]
|
|
(i);
|
|
|
|
cout << i << endl;
|
|
|
|
the output is : 0 1
|
|
|
|
Reference preservation is necessary because we need to have L-value access to
|
|
outer lambda-scopes (especially the arguments). `arg`s and `ref`s are L-values.
|
|
`val`s are R-values.
|
|
|
|
[*Visibility]
|
|
[#phoenix.modules.scope.let.visibility]
|
|
|
|
The scope and lifetimes of the local variables is limited within the let-body.
|
|
`let` blocks can be nested. A local variable may hide an outer local variable.
|
|
For example:
|
|
|
|
let(_x = _1, _y = _2)
|
|
[
|
|
// _x here is an int: 1
|
|
|
|
let(_x = _3) // hides the outer _x
|
|
[
|
|
cout << _x << _y // prints "Hello, World"
|
|
]
|
|
](1," World","Hello,");
|
|
|
|
The actual values of the parameters _1, _2 and _3 are supplied from the
|
|
bracketed list at the end of the `let`.
|
|
|
|
There is currently a limitation that the inner `let` cannot be supplied with a
|
|
constant e.g. `let(_x = 1)`.
|
|
|
|
The RHS (right hand side lambda-expression) of each local-declaration cannot
|
|
refer to any LHS local-id. At this point, the local-ids are not in scope yet;
|
|
they will only be in scope in the let-body. The code below is in error:
|
|
|
|
let(
|
|
_a = 1
|
|
, _b = _a // Error: _a is not in scope yet
|
|
)
|
|
[
|
|
// _a and _b's scope starts here
|
|
/*. body .*/
|
|
]
|
|
|
|
However, if an outer let scope is available, this will be searched. Since
|
|
the scope of the RHS of a local-declaration is the outer scope enclosing
|
|
the let, the RHS of a local-declaration can refer to a local variable of
|
|
an outer scope:
|
|
|
|
let(_a = 1)
|
|
[
|
|
let(
|
|
_a = _1
|
|
, _b = _a // Ok. _a refers to the outer _a
|
|
)
|
|
[
|
|
/*. body .*/
|
|
]
|
|
](1)
|
|
|
|
[endsect]
|
|
[section lambda]
|
|
|
|
#include <boost/phoenix/scope/lambda.hpp>
|
|
|
|
A lot of times, you'd want to write a lazy function that accepts one or more
|
|
functions (higher order functions). STL algorithms come to mind, for example.
|
|
Consider a lazy version of `stl::for_each`:
|
|
|
|
struct for_each_impl
|
|
{
|
|
template <typename C, typename F>
|
|
struct result
|
|
{
|
|
typedef void type;
|
|
};
|
|
|
|
template <typename C, typename F>
|
|
void operator()(C& c, F f) const
|
|
{
|
|
std::for_each(c.begin(), c.end(), f);
|
|
}
|
|
};
|
|
|
|
function<for_each_impl> const for_each = for_each_impl();
|
|
|
|
Notice that the function accepts another function, `f` as an argument. The scope
|
|
of this function, `f`, is limited within the `operator()`. When `f` is called
|
|
inside `std::for_each`, it exists in a new scope, along with new arguments and,
|
|
possibly, local variables. This new scope is not at all related to the outer
|
|
scopes beyond the `operator()`.
|
|
|
|
Simple syntax:
|
|
|
|
lambda
|
|
[
|
|
lambda-body
|
|
]
|
|
|
|
Like `let`, local variables may be declared, allowing 1..N local variable
|
|
declarations (where N == `BOOST_PHOENIX_LOCAL_LIMIT`):
|
|
|
|
lambda(local-declarations)
|
|
[
|
|
lambda-body
|
|
]
|
|
|
|
The same restrictions apply with regard to scope and visibility. The RHS
|
|
(right hand side lambda-expression) of each local-declaration cannot refer
|
|
to any LHS local-id. The local-ids are not in scope yet; they will be in
|
|
scope only in the lambda-body:
|
|
|
|
lambda(
|
|
_a = 1
|
|
, _b = _a // Error: _a is not in scope yet
|
|
)
|
|
|
|
See [link phoenix.modules.scope.let.visibility `let` Visibility] for more information.
|
|
|
|
Example: Using our lazy `for_each` let's print all the elements in a container:
|
|
|
|
for_each(arg1, lambda[cout << arg1])
|
|
|
|
As far as the arguments are concerned (arg1..argN), the scope in which the
|
|
lambda-body exists is totally new. The left `arg1` refers to the argument passed
|
|
to `for_each` (a container). The right `arg1` refers to the argument passed by
|
|
`std::for_each` when we finally get to call `operator()` in our `for_each_impl`
|
|
above (a container element).
|
|
|
|
Yet, we may wish to get information from outer scopes. While we do not have
|
|
access to arguments in outer scopes, what we still have is access to local
|
|
variables from outer scopes. We may only be able to pass argument related
|
|
information from outer `lambda` scopes through the local variables.
|
|
|
|
[note This is a crucial difference between `let` and `lambda`: `let`
|
|
does not introduce new arguments; `lambda` does.]
|
|
|
|
Another example: Using our lazy `for_each`, and a lazy `push_back`:
|
|
|
|
struct push_back_impl
|
|
{
|
|
template <typename C, typename T>
|
|
struct result
|
|
{
|
|
typedef void type;
|
|
};
|
|
|
|
template <typename C, typename T>
|
|
void operator()(C& c, T& x) const
|
|
{
|
|
c.push_back(x);
|
|
}
|
|
};
|
|
|
|
function<push_back_impl> const push_back = push_back_impl();
|
|
|
|
write a lambda expression that accepts:
|
|
|
|
# a 2-dimensional container (e.g. `vector<vector<int> >`)
|
|
# a container element (e.g. `int`)
|
|
|
|
and pushes-back the element to each of the `vector<int>`.
|
|
|
|
Solution:
|
|
|
|
for_each(arg1,
|
|
lambda(_a = arg2)
|
|
[
|
|
push_back(arg1, _a)
|
|
]
|
|
)
|
|
|
|
Since we do not have access to the arguments of the outer scopes beyond the
|
|
lambda-body, we introduce a local variable `_a` that captures the second outer
|
|
argument: `arg2`. Hence: _a = arg2. This local variable is visible inside the
|
|
lambda scope.
|
|
|
|
(See [@../../example/lambda.cpp lambda.cpp])
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|