C++ Basics: Understanding Lambda. A convenient way to define a functor... | by Debby Nirwan | Towards Data Science

One of the new features introduced in Modern C++ starting from C++11 is Lambda Expression.
It is a convenient way to define an anonymous function object or functor. It is convenient because we can define it locally where we want to call it or pass it to a function as an argument.
Lambda is easy to read too because we can keep everything in the same place.
In this post, we’ll look at what a lambda is, compare it with a function object (functor), and more importantly understand what it actually is and how to think about it when coding in C++.
This is how we define a lambda in C++:
plus_one in this code is a functor under the hood. Let’s now first see what a functor is.
According to Wikipedia, A function object or usually referred to as a functor is a construct that allows an object to be called as if it were an ordinary function.
The keyword here is the “ordinary function”. In C++ we can overload operator () to implement a functor. Here is a functor that behaves the same as our lambda:
One example of the advantages of using a functor over an ordinary function is that it can access the internal member variables and functions of that object.
It will be clearer when we want to create functions “plus one”, “plus two”, etc. By using a functor we don’t have to define multiple functions with unique names.
As you can see, at the caller side it looks like a call to an ordinary function.
How does it look like at the machine level? Well, a functor is an object so it has member variables and member functions. The ordinary function is as follows:
int plus_one(const int value){  return value + 1;}
whereas a functor is as follows:
int PlusOne::operator()(const PlusOne* this, const int value){  return value + this->data;}
If we already have a functor which in some scenarios is better than an ordinary function, why do we need lambda?
Lambda offers a simpler way to write a functor. It is a syntactic sugar for an anonymous functor. It reduces the boilerplate that we need to write in a functor.
To see how lambda simplifies a functor, we create a lambda for our Plus class above.
We can remove a lot of boilerplate code from our functor above. We know that our functor looks like this:
int PlusOne::operator()(const PlusOne* this, const int value){  return value + this->data;}
What about our lambda? By assuming we define our lambda inside our main function this is how it looks like:
int main::lambda::operator()(const lambda* hidden, const int value){  return value + hidden->data;}
It’s very much similar to our functor other than the name. So now we know that our lambda is just a functor, without a name and with a simplified form.
Another thing that you may notice is the hidden pointer’s name isn’t called this because the this keyword is used for the outer scope’s object.
Both functors and lambdas are often used for writing callback functions. They are very useful when we deal with STL algorithms. For example when we want to transform our data stored in a std::vector. With a functor we can write it as follows:
After calling std::transform, we’ll get {2, 3, 4, 5}. With lambda this is how we write it:
We can see that it is much neater with a lambda where we can read the code without having to jump to another place to see what operation is done to transform our test_data.
We should think about a lambda as an object, to create and initialize member variables we use the capture ‘[]’ mechanism. To create and initialize a variable we can simply write it in ‘[]’:
auto return_one = [value=1](){ return value; };
We can also make a copy of another object in the scope:
void func(){  int a = 1;  // by value  auto return_one = [value=a](){ return value; };}void func(){  int a = 1;  // by reference  auto return_one = [&value=a](){ return value; };}
Some other things that are important to know about lambdas are:
It can be converted to a raw function pointer if it doesn’t capture
The code above won’t compile because the lambda is not convertible to a function pointer according to the standard, the most obvious reason is that there is a hidden parameter in the operator(). But it is convertible if it doesn’t capture, so the following compiles:
This is because there exists a user-defined conversion function for capture-less lambdas.
int(*GetValue)() = [](){return 1;}
By default the overloaded operator() is const
This code won’t compile because we are trying to modify a member variable in a const function. Remember that it looks like this under the hood:
int main::lambda::operator()(const lambda* hidden){  return hidden->value++;}
The hidden pointer points to a constant lambda object hence the error. To modify the captured variable, we add a mutable keyword as follows:
We have seen one way to pass a lambda as an argument above, via conversion to a raw function pointer. But that only works for capture-less lambdas.
There are two ways to pass lambdas as arguments of functions:
The STL way, with template
Use std::function
We have seen that lambda is just a convenient way to write a functor, therefore we should always think about it as a functor when coding in C++.
We should use lambdas where we can improve the readability of and simplify our code such as when writing callback functions.
I hope this post is useful for you because starting from the basics will help us in the long term.
Here are some useful references: