The use case for lambdas are those situations where you need to create a simple small function object that is not meant to be reused. Lambdas represent a simple way of doing so. Some of the basic use cases will involve using the standard library algorithms:
std::vector<double> data = get_data();
std::transform( data.begin(), data.end(), data.begin(), [](double x){ return x*x*height; } );
That is a simple concise way of iterating over a container of double performing an operation to all the elements. Before C++0x you needed to create a function or function object to pass as an argument. The language did not allow local types to be used with templates which meant that you needed to go outside of the function you are implementing to create just a simple function.
Lambdas are not really an enabling feature (they don't allow you to do anything that couldn't be done without them). As an example, in C++0x local types can be used with templates (there was never a reason to disallow it, it just happened to be), so you could write:
std::vector<double> data = get_data();
struct operation { // 1
double h; // 2
operation( double h ) : h(h) {} // 3
double operator()( double x ) { return x*x*h; } // 4
};
std::transform( data.begin(), data.end(), data.begin(), operation(height) );
The code does basically the same thing, but there is a bit of extra boiler plate (code that is not part of the logic, but is needed for the language. You need to declare it to be a type [1], and provide the implementation of operator() [4]. Because local types do not capture anything from the context you need to create a member attribute to hold the height [2], and you need to pass it in the construction [3]. Lambdas just allow a concise way of expressing that.
There are multiple other situations where you might want to create small function objects that perform a small operation and lambdas might help. Consider, for example printing the contents of the vector above. It could be done in C++03 as:
std::copy( data.begin(), data.end(), std::ostream_iterator<double>(std::cout, " ") );
Or with a simple lambda:
std::for_each( data.begin(), data.end(), []( double x ) { std::cout << x << " "; } );
Which is more readable in this case? Either one, but there are many circumstances where there is no iterator adaptor (std::ostream_iterator) or prebuilt functor that fits your needs. Finally, you can think that lambdas might be used to remove the need for std::bind to create generalized functors.
Currently (with boost::bind, or in C++0x without lambdas) you can create a function adapters with bind. One piece of code that I have used this before was while writing a Timer type. The idea is that you create one such object, and you register callbacks with a given period. Every time that the period completes, the timer will call all of the registered objects.
struct console {
std::ostream& out;
console( std::ostream& o ) : out(o) {}
void print( std::string const & msg ) {
out << msg;
}
};
Timer t;
console c( std::cout );
console e( std::cerr );
t.register( 1, std::bind(&console::print, &c, ".") );
t.register( 5, std::bind(&console::print, &e, "E") );
Assume that console is a much more complex class. The generalized function lets you adapt the signature of the caller (the timer will call a function<void ()>) with the signature of the function being called. In this case, it ill call the print method in an object of type console adding an extra argument. The above code will print . every second to cout, and E every 5 seconds to cerr. The registration of the callbacks can be replaced by a lambda:
t.register( 1, [&c]() { c.print("."); });
t.register( 5, [&e]() { e.print("E"); });
Again, nothing new, the same thing can be achieved with a generalized functor (or with more code with a local type), but it improves usability of the language.
Overall, what lambdas let you do is creating concise in place functions when you don't need that functionality to be reused from other parts of the code.