I was reading the chapter on generic algorithms in C++ Primer 5th Edition, Lipman,Lajoie, Moo. I was just trying to get a general idea of what algorithms were available and the syntax for using them. Up to a point I understood what was written.
Then I came to the section on lambdas and it is quite a big section. As I was reading this I kept thinking WTF , as none of it made any sense to me. About all I picked up was that they were functions and that's about it.
What I want to know is:
1. In plain English, what are lambdas and when do you use them?
2. Can I happily get on writing code without lambdas. That is, are there easier alternative ways to achieve whatever they are supposed to do?
> In plain English, what are lambdas and when do you use them?
A lambda expression is a mechanism for specifying a function object. The primary use for a lambda is to specify a simple action to be performed by some function. http://www.stroustrup.com/C++11FAQ.html#lambda
> Can I happily get on writing code without lambdas
Yes. Function objects can provide equivalent functionality. In many situations (small, local anonymous function, often with with lexical closure) lambda expressions would be easier; more apt.
They are expressions that, when evaluated, produce an object of a class that the compiler writes for you, in fewer lines of code than you would have to do yourself.
For example, suppose you want to add the sum of the lengths of the strings in some container to a variable called 'n'
Old way:
1 2 3 4 5 6 7 8
struct AddSizeTo {
int& sum;
AddSizeTo(int& n) : sum(n) {}
voidoperator()(const std::string& s) { sum += s.size(); }
};
...
int n = start_value;
for_each(v.begin(), v.end(), AddSizeTo(n));
New way:
1 2
int n = start_value;
for_each(v.begin(), v.end(), [&](const std::string& s){n += s.size();});
This does exact same thing: the compiler writes a class with a member whose type is reference to int, writes a constructor for it that takes a reference to int, and writes an operator() that does what it does. Only in less code. And the name of the class the compiler wrote is kept secret.
@Cubbi thanks for your explanation. At least I know they are not functions. At the moment I can't see myself ever needing to use them so I plan to skip over this topic as it seems rather complex.
int init = 0;
for ( size_t i = 0; i < arr.size(); ++i )
{
init = init + arr[i];
}
int sum = init;
The code in the body of the loop could get large, so one could move it into separate function:
1 2 3 4 5 6 7 8 9 10 11 12 13
int binary_op( int lhs, int rhs )
{
return lhs + rhs;
}
// ...
int init = 0;
for ( size_t i = 0; i < arr.size(); ++i )
{
init = binary_op( init, arr[i] );
}
int sum = init;
Now it should become obvious that writing that loop is rather boring and doing it many times will likely introduce some typos. Hence the standard algorithms:
1 2 3 4 5 6 7 8
int binary_op( int lhs, int rhs )
{
return lhs + rhs;
}
// ...
int sum = std::accumulate( begin(arr), end(arr), 0, binary_op );
But wait, our loop body is really simple. Having it separate, potentially far from point of use seems silly. Here does the lambda step in. Define the (nameless) function right there (where the algorithm expects a functor):
int sum = std::accumulate( begin(arr), end(arr), 0, [](int lhs, int rhs){return lhs+rhs;} );
Compact, yet expressive.
Think about a function object with a state. Say a struct that does some procedure and keeps track of how many times it has been called. It does need a member variable for the counter. You need to define that struct somewhere. A lambda can capture a variable:
1 2 3 4
size_t count = 0;
int sum = std::accumulate( begin(arr), end(arr), 0,
[&](int lhs, int rhs){++count; return lhs+rhs;} );
// count has changed
But, you don't have to use lambdas:
1 2 3 4 5 6
size_t count = 0;
int sum = 0;
while ( count < arr.size() )
{
sum += arr[count++];
}