Biểu thức Lambda (hàm ẩn danh) là một tính năng mạnh mẽ trong C++ được giới thiệu từ C++11, thường được sử dụng khi cần tạo các hàm tạm thời như trong std::sort, std::for_each hoặc các callback luồng.
1. Cú pháp cơ bản của Lambda
[capture](parameters) -> return_type {
// thân hàm
};
- capture: Dùng để bắt giữ các biến từ phạm vi hiện tại.
- parameters: Danh sách tham số.
- return_type: Có thể bỏ qua để compiler suy diễn.
- body: Nội dung hàm.
2. Ví dụ minh họa
2.1 Lambda đơn giản nhất
auto inChao = []() {
std::cout << "Chào từ lambda!" << std::endl;
};
inChao(); // Gọi hàm
2.2 Lambda có tham số và giá trị trả về
auto tongHaiSo = [](int a, int b) -> int {
return a + b;
};
std::cout << tongHaiSo(3, 4); // In ra 7
Kiểu trả về có thể lược bỏ nhờ suy diễn tự động.
2.3 Bắt giữ biến ngoài (giá trị vs tham chiếu)
int a = 10, b = 20;
// Bắt giữ bằng giá trị
auto bangGiaTri = [a, b]() {
std::cout << "Bắt giữ: " << a + b << std::endl;
};
// Bắt giữ bằng tham chiếu
auto bangThamChieu = [&a, &b]() {
a += 1; b += 1;
};
bangGiaTri(); // In 30
bangThamChieu(); // Thay đổi a và b
2.4 Bắt giữ tự động: = và &
int x = 1, y = 2;
auto lambda1 = [=]() { std::cout << x + y << std::endl; }; // Bắt giữ tất cả bằng giá trị
auto lambda2 = [&]() { x += 10; y += 10; }; // Bắt giữ tất cả bằng tham chiếu
2.5 Sử dụng với std::sort
std::vector<int> v = {4, 2, 5, 1, 3};
std::sort(v.begin(), v.end(), [](int a, int b) {
return a > b; // Sắp xếp giảm dần
});
2.6 Lambda có trạng thái với mutable
int dem = 0;
auto lambda = [dem]() mutable {
dem++;
std::cout << dem << std::endl;
};
lambda(); lambda(); // In ra 1, 2 - Bản sao được thay đổi nhờ mutable
2.7 Kết hợp với thuật toán chuẩn
std::vector<int> duLieu = {1, 2, 3, 4, 5};
std::for_each(duLieu.begin(), duLieu.end(), [](int giaTri) {
std::cout << giaTri << " ";
});
2.8 Truyền làm tham số
void thucThiLambda(const std::function<void(int)>& func) {
func(100);
}
int main() {
thucThiLambda([](int x) {
std::cout << "Giá trị: " << x << std::endl;
});
}
3. Những điểm cần lưu ý
| Điểm chú ý | Mô tả |
|---|---|
| Phương thức bắt giữ | \[=\] sao chép giá trị, \[&\] bắt giữ tham chiếu |
| mutable | Biến bắt giữ theo giá trị mặc định là hằng, cần thêm mutable để thay đổi |
| Thời gian sống | Dùng tham chiếu biến cục bộ sau khi hàm kết thúc sẽ gây ra truy cập vùng nhớ treo |
| Suy diễn kiểu | Compiler tự động xác định kiểu trả về trừ khi có nhiều nhánh khác nhau |
| Loại đối tượng | Lambda là lớp ẩn danh, dùng auto hoặc std::function để lưu trữ |
4. Ứng dụng nâng cao
4.1 Hàm đóng gói có trạng thái
auto demSo = []() {
int dem = 0;
return [=]() mutable {
return ++dem;
};
}();
std::cout << demSo() << std::endl; // 1
std::cout << demSo() << std::endl; // 2
4.2 Bắt giữ this trong Lambda
class ThietKe {
public:
void thucHien() {
int giaTri = 42;
auto l = [this, giaTri]() {
std::cout << "giaTri = " << giaTri << ", thanhVien = " << this->thanhVien << std::endl;
};
l();
}
private:
int thanhVien = 99;
};