lambda
C++ lambda expressions, introduced in C++11, define anonymous functions inline. Their key feature is the capture list, which takes variables from the enclosing scope by value or by reference. Lambdas combine especially well with STL algorithms.
Syntax
// [capture list](parameters) -> return type { body }
// Return type can be omitted; the compiler infers it.
// Simplest lambda: no captures
auto greet = []() {
// body
};
// Lambda with parameters
auto add = [](int a, int b) -> int {
return a + b;
};
// Return type omitted — compiler infers it
auto multiply = [](int a, int b) {
return a * b;
};
// Value capture: takes a copy of x
int x = 10;
auto printX = [x]() {
// changes to the external x do not affect this copy
};
// Reference capture: holds a reference to counter
int counter = 0;
auto increment = [&counter]() {
counter++; // modifies the external counter directly
};
// [=] captures all variables by value; [&] by reference
auto captureAll = [=]() { /* copy of all outer variables */ };
auto captureRef = [&]() { /* reference to all outer variables */ };
// mutable: allows modifying the captured copy inside the lambda
auto mutableLambda = [x]() mutable {
x++; // only the copy changes; external x is unchanged
};
Capture Reference
| Capture Notation | Description |
|---|---|
| [] | Captures nothing. For lambdas that use no external variables. |
| [x] | Captures x by value (copy). Changes inside the lambda do not affect the original. |
| [&x] | Captures x by reference. Changes inside the lambda directly affect the original. |
| [=] | Captures all variables in scope by value. |
| [&] | Captures all variables in scope by reference. |
| [=, &x] | Default value capture, but x is captured by reference. |
| [&, x] | Default reference capture, but x is captured by value. |
| mutable | Allows modifying the value-captured copy inside the lambda body. External variables are unchanged. |
Sample Code
kiryu_lambda.cpp
// kiryu_lambda.cpp
// Lambda expression sample using Yakuza (Like a Dragon) characters.
// Demonstrates capture types and use with STL algorithms.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
struct Character {
std::string name;
std::string role;
int heat;
};
int main() {
// 1. No capture: simple separator lambda
auto printSeparator = []() {
std::cout << "==============================" << std::endl;
};
printSeparator();
std::cout << "Yakuza Lambda Sample" << std::endl;
printSeparator();
// 2. Value capture: takes a copy of protagonist and baseHeat
std::string protagonist = "Kiryu Kazuma";
int baseHeat = 50;
auto showHero = [protagonist, baseHeat]() {
std::cout << "Protagonist: " << protagonist
<< " Base Heat: " << baseHeat << std::endl;
};
showHero();
baseHeat = 999;
std::cout << "Even after changing baseHeat, the captured copy is unchanged:" << std::endl;
showHero(); // still shows 50
printSeparator();
// 3. Reference capture: modifies totalBattles directly
int totalBattles = 0;
auto recordBattle = [&totalBattles](const std::string& winner) {
totalBattles++;
std::cout << "Battle #" << totalBattles << " winner: " << winner << std::endl;
};
recordBattle("Kiryu Kazuma");
recordBattle("Majima Goro");
recordBattle("Nishikiyama Akira");
std::cout << "Total battles (updated via reference): " << totalBattles << std::endl;
printSeparator();
// 4. Lambda as comparator for std::sort
std::vector<Character> characters;
characters.push_back({"Kiryu Kazuma", "Protagonist", 90});
characters.push_back({"Majima Goro", "Mad Dog", 95});
characters.push_back({"Shimano Futoshi", "Executive", 70});
characters.push_back({"Nishida Junichi", "Sub-boss", 65});
characters.push_back({"Nishikiyama Akira", "Kiryu's brother", 80});
std::sort(characters.begin(), characters.end(),
[](const Character& a, const Character& b) {
return a.heat > b.heat; // descending
}
);
std::cout << "--- Heat Gauge (descending) ---" << std::endl;
for (int i = 0; i < (int)characters.size(); i++) {
std::cout << characters[i].name << " (" << characters[i].role << ")"
<< " Heat: " << characters[i].heat << std::endl;
}
printSeparator();
// 5. Lambda as predicate for std::find_if
int threshold = 85;
auto it = std::find_if(characters.begin(), characters.end(),
[threshold](const Character& c) {
return c.heat >= threshold;
}
);
if (it != characters.end()) {
std::cout << "First character with heat >= " << threshold << ": "
<< it->name << " (heat: " << it->heat << ")" << std::endl;
}
printSeparator();
// 6. mutable: allows modifying the value-captured copy
int heatLevel = 0;
auto chargeHeat = [heatLevel]() mutable {
heatLevel += 10;
std::cout << "Charging… internal heatLevel: " << heatLevel << std::endl;
};
chargeHeat();
chargeHeat();
chargeHeat();
std::cout << "External heatLevel is unchanged: " << heatLevel << std::endl;
printSeparator();
// 7. Lambda returning a lambda (closure)
auto makeHeatBooster = [](int bonus) {
return [bonus](const Character& c) {
std::cout << c.name << " heat: " << c.heat
<< " → " << c.heat + bonus << " (+" << bonus << ")" << std::endl;
};
};
auto boostBy20 = makeHeatBooster(20);
std::cout << "--- Heat Boost (+20) ---" << std::endl;
boostBy20(characters[0]);
boostBy20(characters[1]);
printSeparator();
return 0;
}
g++ -std=c++11 kiryu_lambda.cpp -o kiryu_lambda ./kiryu_lambda ============================== Yakuza Lambda Sample ============================== Protagonist: Kiryu Kazuma Base Heat: 50 Even after changing baseHeat, the captured copy is unchanged: Protagonist: Kiryu Kazuma Base Heat: 50 ============================== Battle #1 winner: Kiryu Kazuma Battle #2 winner: Majima Goro Battle #3 winner: Nishikiyama Akira Total battles (updated via reference): 3 ============================== --- Heat Gauge (descending) --- Majima Goro (Mad Dog) Heat: 95 Kiryu Kazuma (Protagonist) Heat: 90 Nishikiyama Akira (Kiryu's brother) Heat: 80 Shimano Futoshi (Executive) Heat: 70 Nishida Junichi (Sub-boss) Heat: 65 ============================== First character with heat >= 85: Majima Goro (heat: 95) ============================== Charging… internal heatLevel: 10 Charging… internal heatLevel: 20 Charging… internal heatLevel: 30 External heatLevel is unchanged: 0 ============================== --- Heat Boost (+20) --- Majima Goro heat: 95 → 115 (+20) Kiryu Kazuma heat: 90 → 110 (+20) ==============================
Common Mistake 1: Reference-captured local variable goes out of scope
A reference capture ([&x]) holds a reference to a local variable. If the variable's lifetime ends before the lambda is called, the reference is dangling — accessing it is undefined behavior. When a lambda outlives the captured variable, use value capture instead.
// NG: name is destroyed when makeLambda returns
auto makeLambda = []() {
std::string name = "Majima Goro";
return [&name]() { // captures a reference to name
std::cout << name << std::endl;
};
};
auto lambda = makeLambda();
lambda(); // undefined behavior: name no longer exists
OK: capture by value so a copy of name survives inside the lambda.
// OK:
auto makeLambda = []() {
std::string name = "Majima Goro";
return [name]() { // copy is stored inside the lambda
std::cout << name << std::endl;
};
};
auto lambda = makeLambda();
lambda(); // prints "Majima Goro"
Common Mistake 2: Modifying a value-captured variable without mutable
A value-captured variable is const by default inside the lambda body. Trying to modify it without mutable is a compile error.
// NG: compile error — value-captured variable is const
int heatLevel = 0;
auto charge = [heatLevel]() {
heatLevel++; // error: assignment to const
};
OK: add mutable to allow modifying the captured copy.
// OK:
auto charge = [heatLevel]() mutable {
heatLevel++; // modifies the copy; external heatLevel unchanged
};
Overview
Lambda expressions, introduced in C++11, are written as [capture](params) -> return_type { body }. The capture list is their defining feature: [x] copies the variable, [&x] holds a reference. [=] copies all outer variables; [&] references all of them. To modify a value-captured variable inside the lambda, add mutable; only the copy is changed — the original is unaffected. Lambdas are particularly powerful in combination with STL algorithms such as std::sort() and std::find_if(). A lambda that returns another lambda acts as a closure, generating functions with specific parameters baked in. The return type can usually be omitted because the compiler infers it.
If you find any errors or copyright issues, please contact us.