Welcome back! I hope you enjoyed our last excursion into lambda expressions. I was looking at my personal code archive where I learned how to write lambdas and I realized that there was a really important bridge to understand how lambdas work, and so today, instead of talking about lambda filtering (we'll do that next time!) I thought we should instead talk about Functors and how they work, because once you see how a functor works, a lambda makes a LOT more sense!

Ok, so, let's just dive right in and take a look at a simple functor:

struct PrintFunctor
{
    void operator()(int x) const
    {
        std::cout << x << std::endl;
    }
};

Ok, a lot to unpack here, this looks something like a simple class, right? The key thing to notice here is about the operator() . I am sometimes surprised by some of the things I've learned about this language over the years, one of my favorite surprises was the larger concept of operators, but I'll talk about that another time... For now, all you need to understand is that when you call PrintFunctor() , it will execute the code in this operator() function. You could also write it like PrintFunctor::operator(), what the word "operator" designates here is what happens when you use the symbols that follow the term. Another example is operator-> which you should be familiar with as the way to access a member on a pointer. Did you know you could actually change what -> does like this? CRAZY, RIGHT? :)

Ok, so we can use the () operator on our PrintFunctor struct and what will happen? Well, we need to look a little bit further, because we also have arguments to the operator, in this case (int x). Just like the lambda, this allows us to name the predicate. Again, totally voodoo magic, but if you provide PrintFunctor to the predicate argument of an STL Algorithm like std::for_each then you'll get that element from your collection named x in your functor.

Let's take what we had last week with the std::vector<int> CollectionToIterate{ 11, 21, 31, 41 }; If you used this PrintFunctor, what would happen?

Did you guess that you'd write "11" "21" "31" "41" to the console? You're right! So, can we write this as a lambda? HECK YES WE CAN!!!

[&](int x) { std::cout << x << std::endl; }

WOW! That's so much smaller, but it does the same thing! Functors can also be used for so many other clever things, and I'll definitely dig into them some more in the future, but for now, let's show a couple lines of code using both a functor and a lambda:

std::for_each(CollectionToIterate.cbegin(), CollectionToIterate.cend(),
PrintFunctor());

Using our PrintFunctor::operator(), the console will see the numbers printed out.

std::for_each(CollectionToIterate.cbegin(), CollectionToIterate.cend(),
[&](auto& element) { std::cout << element << std::endl; });

OOOOOH, I threw you a curve ball! Do you see what I did here? I changed the name and type of the predicate from int x to auto& element. Lambdas give you a bit more flexibility than functors for some things, but this is the great thing about it. You can write a functor in a single line of code. We call them lambdas.

I hope this helps you the way it helped me to understand these. A lambda is basically just a small special class object that does one discreet thing. But they're even more flexible than that, so, next time, I promise we'll get into the collection filtering with lambdas! Thanks for reading!