C++ Lambda Functions
Published: September 15, 2025 | Tags: #c++ #cpp #programming #lambdas
Have you ever needed a quick function, but you think that declaring it somewhere else can be a bit of an overkill? In modern C++, the solution can be found from the world of functional programing. Lambda functions must it be.
Lambdas are anonymous, inline functions that you can define anywhere quickly. For short tasks it can be useful to improve the readability.
Let’s have some fun!
So… why do we need Lambdas?
Before lambdas were introduced in C++11, passing a simple operation to an algorithm was kinda messy.
You either had to define a full, named function somewhere else or create a functor (a struct with an overloaded operator()
).
// Functor example, we can make an article for this.
struct myFunctor
{
int operator() (int x, int y) const
{
return x + y;
}
};
To talk about this, let’s sort a vector of custom objects. For example, imagine you have a Person
struct and you want to sort a vector of people by age.
Using a function - the old way.
This works, but compareByAge
is a single-use function that pretty much polutes the global namespace.
It’s also defined far away from where it’s actually used.
#include <iostream>
#include <vector>
#include <algorithm> // For the C++ newbies, this is needed for std::sort
struct Person
{
std::string name;
int age;
};
// The function for the comparison.
bool compareByAge(const Person& a, const Person& b)
{
return a.age < b.age;
}
int main()
{
std::vector<Person> people = {
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35}
};
std::sort(people.begin(), people.end(), compareByAge);
for (const auto& p : people)
{
std::cout << p.name << " (" << p.age << ")\n";
}
return 0;
}
Using a Lambda - the modern way.
Much cleaner! And is located exactly where we need it.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
struct Person
{
std::string name;
int age;
};
int main()
{
std::vector<Person> people = {
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35}
};
std::sort(people.begin(), people.end(), [](const Person& a, const Person& b)
{
return a.age < b.age;
});
for (const auto& p : people)
{
std::cout << " " << p.name << " (" << p.age << ")\n";
}
return 0;
}
Anatomy of a Lambda (dissection time)
A lambda function has a few key parts.
[captures] (parameters) -> return_type { function_body }
-
[]
Capture clause: it specifies which variables from the surrounding scope the lambda czn use. An empty[]
means it captures nothing. -
()
Parameter list: just like a normal function’s parameter list. In ourstd::sort
example, it was(const Person& a, const Person& b)
. -
-> return_type
(optional): the return type. The compiler can deduce this many times, therefore, it’s not that necessary. -
{}
Function body: the actual code you want the lambda to execute.
Magic of captures - Creating a closure
A lambda that captures variables from its environment is called a closure.
This is what makes them more powerful than a simple function pointer.
Let’s try to find all people older than a certain age_limit
.
int age_limit = 30;
std::vector<Person> people = {
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35}
};
auto it = std::find_if(people.begin(), people.end(), [age_limit](const Person& p)
{
return p.age > age_limit;
});
Capture modes
Here’s how the different capture modes work:
-
[]
(No capture): no access to any variables from the outside scope. -
[=]
(capture by value): lambda gets its own copy of all variables used from the surrounding scope.
int x = 10;
auto my_lambda = [=]() { std::cout << x; }; // Makes copy
[&]
(capture by reference): lambda gets a reference to all variables used (IMPORTANT: if the original variable is destroyed before, you’ll have a dangling reference).
int x = 10;
auto my_lambda = [&]() { x++; }; // Accesses the original x
my_lambda();
-
[var]
(specific capture by value): captures only the variablevar
by value. ([var1, var2]
) -
[&var]
(specific Capture by Reference): captures onlyvar
by reference. ([&var1, &var2]
) -
[this]
(capturethis
pointer): lambda can access member variables of the containing class.
Lab Time!
Conclusion
Lambda functions are not just a cute tool (although cute might not be the best expression), but a powerful feature that provides a concise way to define inline, anonymous functions.
And, we all know what they say about C++; not readable at all. Well, lambda functions can clearly help.