Home | Libraries | People | FAQ | More |
Sometimes it is convenient to store lambda functors in variables. However, the types of even the simplest lambda functors are long and unwieldy, and it is in general unfeasible to declare variables with lambda functor types. The Boost Function library[function] defines wrappers for arbitrary function objects, for example lambda functors; and these wrappers have types that are easy to type out. For example:
boost::function<int(int, int)> f = _1 + _2; boost::function<int&(int&)> g = (_1 += 10); int i = 1, j = 2; f(i, j); // returns 3 g(i); // sets i to = 11;
The return and parameter types of the wrapped function object must be written explicilty as the template argument to the wrapper template boost::function; even when lambda functors, which otherwise have generic parameters, are wrapped. Wrapping a function object with boost::function introduces a performance cost comparable to virtual function dispatch, though virtual functions are not actually used. Note that storing lambda functors inside boost::function introduces a danger. Certain types of lambda functors may store references to the bound arguments, instead as taking copies of the arguments of the lambda expression. When temporary lambda functor objects are used in STL algorithm invocations this is always safe, as the lambda functor gets destructed immediately after the STL algortihm invocation is completed. However, a lambda functor wrapped inside boost::function may continue to exist longer, creating the possibility of dangling references. For example:
int* sum = new int(); *sum = 0; boost::function<int&(int)> counter = *sum += _1; counter(5); // ok, *sum = 5; delete sum; counter(3); // error, *sum does not exist anymore
The Boost Bind[bind] library has partially overlapping functionality with the BLL. Basically, the Boost Bind library (BB in the sequel) implements the bind expression part of BLL. There are, however, some semantical differerences.
The BLL and BB evolved separately, and have different implementations. This means that the bind expressions from the BB cannot be used within bind expressions, or within other type of lambda expressions, of the BLL. The same holds for using BLL bind expressions in the BB. The libraries can coexist, however, as the names of the BB library are in boost namespace, whereas the BLL names are in boost::lambda namespace.
The BLL requires a compiler that is reasonably conformant to the C++ standard, whereas the BB library is more portable, and works with a larger set of compilers.
The following two sections describe what are the semantic differences between the bind expressions in BB and BLL.
template<class F> int foo(const F& f) { int x; .. bind(f, _1)(x); ... }
int bar(int, int); nested(bind(bar, 1, _1));The bind expression inside foo becomes:
bind(bind(bar, 1, _1), _1)(x)The BLL interpretes this as:
bar(1, x)(x)whereas the BB library as
bar(1, x)To get this functionality in BLL, the bind expression inside the foo function can be written as:
bind(unlambda(f), _1)(x);as explained in the section called “Unlambda”.
The BB library supports up to nine placeholders, while the BLL defines only three placeholders. The rationale for not providing more, is that the highest arity of the function objects accepted by any STL algorithm is two. The placeholder count is easy to increase in the BB library. In BLL it is possible, but more laborous. The BLL currently passes the actual arguments to the lambda functors internally just as they are and does not wrap them inside a tuple object. The reason for this is that some widely used compilers are not capable of optimizing the intermediate tuple objects away. The creation of the intermediate tuples would cause a significant performance hit, particularly for the simplest (and thus the most common) lambda functors. We are working on a hybrid approach, which will allow more placeholders but not compromise the performance of simple lambda functors.
Copyright © 1999-2004 Jaakko Järvi, Gary Powell |