Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Click here to view the latest version of this page.
PrevUpHomeNext

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 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] 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:

  1. a 2-dimensional container (e.g. vector<vector<int> >)
  2. 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 lambda.cpp)


PrevUpHomeNext