|
| 1 | +Lambdas |
| 2 | +-- |
| 3 | + |
| 4 | +<p align="center"> |
| 5 | + <a href="https://youtu.be/blah"><img src="https://img.youtube.com/vi/blah/maxresdefault.jpg" alt="Video" align="right" width=50% style="margin: 0.5rem"></a> |
| 6 | +</p> |
| 7 | + |
| 8 | +We've talked about so many things, like classes and functions but there is one more thing that modern C++ has that we did not really touch upon - lambdas. |
| 9 | + |
| 10 | +Here's what they are useful for. Imagine we have a vector of people, represented as a struct `Person`, and we would like to sort them by age. We can use the standard [`std::sort`](https://en.cppreference.com/w/cpp/algorithm/sort) function for that. |
| 11 | + |
| 12 | +```cpp |
| 13 | +#include <algorithm> |
| 14 | +#include <iostream> |
| 15 | +#include <string> |
| 16 | +#include <vector> |
| 17 | + |
| 18 | +struct Person { |
| 19 | + std::string name; |
| 20 | + int age; |
| 21 | +}; |
| 22 | + |
| 23 | +void Print(const std::vector<Person>& persons) { |
| 24 | + for (const auto& person : persons) { |
| 25 | + std::cout << person.name << " " << person.age << "\n"; |
| 26 | + } |
| 27 | +} |
| 28 | + |
| 29 | +int main() { |
| 30 | + std::vector<Person> people{ |
| 31 | + {"Gendalf", 55'000}, {"Frodo", 33}, {"Legolas", 2'931}, {"Gimli", 139}}; |
| 32 | + Print(people); |
| 33 | + std::sort( |
| 34 | + people.begin(), people.end(), |
| 35 | + [](const auto& left, const auto& right) { return left.age < right.age; }); |
| 36 | + std::cout << "------ sorted --------" << std::endl; |
| 37 | + Print(people); |
| 38 | +} |
| 39 | +``` |
| 40 | +The third argument to the `std::sort` function here is the lambda expression that essentially stands in for a comparison operator between the objects of the person class. |
| 41 | +
|
| 42 | +So let's talk about lambdas! What they are, how to write them to stay safe and efficient and, yes, how they make this valid C++ code: |
| 43 | +```cpp |
| 44 | +int main() { |
| 45 | + [](){}(); |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | +<!-- Intro --> |
| 50 | + |
| 51 | +## Before lambdas we had functors |
| 52 | +The concept of something "callable" that we can pass into a function or even store for a while is not new to C++. It existed long before lambdas were introduced into the language. |
| 53 | + |
| 54 | +Let's pause for a moment and talk a bit about what it means that something is "callable". Essentially it means that we can call it through a `()` operator with the expected number of arguments. So if we write a function `less(const Person&, const Person&)` and pass its pointer to `std::sort` it will do the trick: |
| 55 | +```cpp |
| 56 | +#include <algorithm> |
| 57 | +#include <iostream> |
| 58 | +#include <string> |
| 59 | +#include <vector> |
| 60 | + |
| 61 | +struct Person { |
| 62 | + std::string name; |
| 63 | + int age; |
| 64 | +}; |
| 65 | + |
| 66 | +void Print(const std::vector<Person>& persons) { |
| 67 | + for (const auto& person : persons) { |
| 68 | + std::cout << person.name << " " << person.age << "\n"; |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +bool less(const Person& p1, const Person& p2) { return p1.age < p2.age; } |
| 73 | + |
| 74 | +int main() { |
| 75 | + std::vector<Person> people{ |
| 76 | + {"Gendalf", 55'000}, {"Frodo", 33}, {"Legolas", 2'931}, {"Gimli", 139}}; |
| 77 | + Print(people); |
| 78 | + std::sort(people.begin(), people.end(), &less); |
| 79 | + std::cout << "------ sorted --------" << std::endl; |
| 80 | + Print(people); |
| 81 | +} |
| 82 | +``` |
| 83 | +
|
| 84 | +But what if this is not enough? What if we need to have a certain state? For example, we wouldn't want to sort the people by their absolute age, but by the difference of their age with respect to some number, say `4242`. |
| 85 | +
|
| 86 | +Behold **function objects**, or **functors**. These are objects for which the function call operator is defined, or, in other words, that define an operator `()`. |
0 commit comments