Giao diện
🎯 Lambda Expressions — Inline Functions
Lambda là anonymous function — viết function ngay tại chỗ cần dùng, không cần đặt tên riêng.
Lambda Syntax
cpp
[capture](parameters) -> return_type { body }┌─────────────────────────────────────────────────────────────────┐
│ LAMBDA ANATOMY │
├─────────────────────────────────────────────────────────────────┤
│ │
│ [=, &x](int a, int b) -> double { return a + b + x; } │
│ │ │ │ │ │
│ │ │ │ └── Body │
│ │ │ └── Return type (optional) │
│ │ └── Parameters │
│ └── Capture list │
│ │
└─────────────────────────────────────────────────────────────────┘Basic Lambda Examples
Simplest Lambda
cpp
#include <iostream>
int main() {
// Lambda không capture, không params
auto greet = []() {
std::cout << "Hello, Lambda!" << std::endl;
};
greet(); // Hello, Lambda!
// Lambda với params
auto add = [](int a, int b) {
return a + b;
};
std::cout << add(3, 4) << std::endl; // 7
// Lambda inline
std::cout << [](int x) { return x * x; }(5) << std::endl; // 25
return 0;
}Lambda với Return Type
cpp
// Automatic return type deduction
auto multiply = [](int a, int b) {
return a * b; // Returns int
};
// Explicit return type (cần thiết khi có nhiều return paths khác type)
auto divide = [](int a, int b) -> double {
if (b == 0) return 0.0;
return static_cast<double>(a) / b;
};
std::cout << divide(5, 2) << std::endl; // 2.5Capture List — Biến bên ngoài
Capture by Value [=]
cpp
int x = 10;
int y = 20;
// Capture ALL by value
auto f1 = [=]() {
std::cout << x + y << std::endl; // 30
// x = 50; // ❌ Error: captured by value = const!
};
// Capture specific by value
auto f2 = [x]() {
std::cout << x << std::endl; // 10
};
x = 100; // Change original
f1(); // Still prints 30 (captured value)Capture by Reference [&]
cpp
int counter = 0;
// Capture ALL by reference
auto increment = [&]() {
++counter; // ✅ Modifies original
};
increment();
increment();
std::cout << counter << std::endl; // 2
// Capture specific by reference
auto f = [&counter]() {
counter *= 2;
};Mixed Capture
cpp
int x = 1, y = 2, z = 3;
// Default by value, z by reference
auto f1 = [=, &z]() {
// x, y captured by value (read-only)
// z captured by reference (modifiable)
z = x + y;
};
// Default by reference, x by value
auto f2 = [&, x]() {
// y, z captured by reference
// x captured by value
y = x * 10;
};Capture Summary
| Syntax | Meaning |
|---|---|
[] | Không capture gì |
[x] | x by value |
[&x] | x by reference |
[=] | All by value |
[&] | All by reference |
[=, &x] | All by value, x by ref |
[&, x] | All by ref, x by value |
[this] | this pointer (trong class) |
[*this] | Copy of *this (C++17) |
mutable Lambdas
Mặc định, biến capture by value là const. Dùng mutable để modify:
cpp
int x = 10;
// ❌ Error without mutable
// auto f = [x]() { x++; return x; };
// ✅ OK with mutable
auto f = [x]() mutable {
x++; // Modifies local copy
return x;
};
std::cout << f() << std::endl; // 11
std::cout << f() << std::endl; // 12
std::cout << x << std::endl; // 10 (original unchanged)Generic Lambdas (C++14)
cpp
// C++14: auto parameters
auto print = [](auto x) {
std::cout << x << std::endl;
};
print(42); // int
print(3.14); // double
print("Hello"); // const char*
// Generic with multiple params
auto add = [](auto a, auto b) {
return a + b;
};
std::cout << add(1, 2) << std::endl; // 3 (int)
std::cout << add(1.5, 2.5) << std::endl; // 4.0 (double)
std::cout << add(std::string("Hello "), std::string("World")) << std::endl;Init Capture (C++14)
cpp
// Move-only types
auto ptr = std::make_unique<int>(42);
// ❌ Cannot capture unique_ptr by value (non-copyable)
// auto f = [ptr]() { };
// ✅ Move into lambda
auto f = [p = std::move(ptr)]() {
std::cout << *p << std::endl;
};
f(); // 42
// Create new variable in capture
auto g = [y = 10 * 2]() {
return y; // 20
};Lambda với STL Algorithms
std::sort với Lambda
cpp
#include <algorithm>
#include <vector>
std::vector<int> v = {5, 2, 8, 1, 9};
// Ascending (default)
std::sort(v.begin(), v.end());
// Descending với lambda
std::sort(v.begin(), v.end(), [](int a, int b) {
return a > b; // Greater = earlier
});
// [9, 8, 5, 2, 1]std::find_if
cpp
std::vector<int> v = {1, 2, 3, 4, 5, 6};
// Tìm số chẵn đầu tiên
auto it = std::find_if(v.begin(), v.end(), [](int x) {
return x % 2 == 0;
});
if (it != v.end()) {
std::cout << "First even: " << *it << std::endl; // 2
}std::transform
cpp
std::vector<int> v = {1, 2, 3, 4, 5};
std::vector<int> squared(v.size());
std::transform(v.begin(), v.end(), squared.begin(),
[](int x) { return x * x; });
// squared = [1, 4, 9, 16, 25]std::for_each
cpp
std::vector<int> v = {1, 2, 3, 4, 5};
std::for_each(v.begin(), v.end(), [](int& x) {
x *= 2;
});
// v = [2, 4, 6, 8, 10]std::count_if
cpp
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int evenCount = std::count_if(v.begin(), v.end(), [](int x) {
return x % 2 == 0;
});
// evenCount = 5Lambda vs Function Pointer
cpp
// Function pointer
bool greaterThan5(int x) { return x > 5; }
void demo() {
std::vector<int> v = {3, 7, 2, 8, 1, 9};
// Function pointer
auto c1 = std::count_if(v.begin(), v.end(), greaterThan5);
// Lambda — inline và có thể capture!
int threshold = 5;
auto c2 = std::count_if(v.begin(), v.end(), [threshold](int x) {
return x > threshold;
});
// Lambda có thể capture, function pointer thì không!
}Immediately Invoked Lambda (IIFE)
cpp
// Gọi ngay lập tức
const auto result = []() {
// Complex initialization
std::vector<int> temp;
for (int i = 0; i < 10; ++i) {
temp.push_back(i * i);
}
return temp;
}(); // () gọi ngay!
// Useful for const initialization
const auto config = []() {
Config c;
c.loadFromFile("settings.json");
c.validate();
return c;
}();Lambda trong Class
cpp
class Button {
std::string label_;
std::function<void()> onClick_;
public:
Button(const std::string& label) : label_(label) {}
void setOnClick(std::function<void()> callback) {
onClick_ = callback;
}
void click() {
if (onClick_) onClick_();
}
};
int main() {
Button btn("Submit");
int counter = 0;
btn.setOnClick([&counter]() {
counter++;
std::cout << "Clicked! Count: " << counter << std::endl;
});
btn.click(); // Clicked! Count: 1
btn.click(); // Clicked! Count: 2
}C++20 Improvements
cpp
// Template lambda
auto add = []<typename T>(T a, T b) {
return a + b;
};
// Lambda with capture default in unevaluated context
// (advanced - for concept constraints)📚 Tổng kết
| Feature | Syntax |
|---|---|
| Basic lambda | [](int x) { return x * 2; } |
| Capture by value | [x] or [=] |
| Capture by ref | [&x] or [&] |
| Mixed | [=, &x] or [&, x] |
| Mutable | [x]() mutable { x++; } |
| Generic (C++14) | [](auto x) { } |
| Init capture (C++14) | [y = expr] or [p = std::move(ptr)] |
| IIFE | []() { }(); |
➡️ Tiếp theo
Tiếp theo: Sorting & Comparators — Custom sort rules.