1. Hàm Lambda là gì ?

  • Có vô số bài viết đã nói về vấn đề này, từ ngôn ngữ đơn giản đến đao to búa lớn đều có hết. Bài viết này mình nói về nó dựa trên những kinh nghiệm bản thân và những gì mình biết về nó (có thể hiểu sai, ai thấy sai thì cứ thoải mái comment nhé ).
  • Nói một cách ngắn gọn thế này thì từ phiên bản C++11 thì mấy anh chị em viết Compiler (Chương trình biên dịch code ra file thực thi cho CPU) giới thiệu một loại hàm mới mà nó chưa từng xuất hiện trước đây. 
  • Đặc điểm khác biệt của nó là nó được khai báo, định nghĩa hàm và gọi chạy luôn trong một dòng lệnh. Giống như vậy nè  a = b + 1; . 
  • Hàm Lambda chưa từng xuất hiện bởi vì trước đây một hàm dù local hay global thì muốn sử dụng chúng ta đều phải khai báo. Tới đây bạn thấy nó chả có ý nghĩa gì đúng không ? Tui muốn dùng một hàm thì khai báo rồi dùng, sài cách Lambda của anh thì được gì hơn? Hãy đọc  phần bên dưới để biết khi nào cần dùng hàm Lambda.

2. Khi nào cần sử dụng hàm Lambda

  • Bản thân mình trong quá trình code thì cũng gặp một vấn đề thế này:
  • Một số hàm chỉ gọi có đúng 1 lần, nếu trong code chỉ có vài hàm như vậy thôi thì sài static hay inline function cũng chập nhận được. Nhưng mà nếu project lớn, có cả trăm cả ngàn hàm như vậy thì việc khai báo rồi sử dụng một lần thì đúng là hơi kì. Do dó nhu cầu có giải pháp khắc phục chỗ này xuất hiện.
  • Thông thường các hàm Callback, hàm ngắt, hàm xử lý event có nhu cầu kiểu này vì nó chỉ được gọi đúng một lần khi sự kiện xảy ra.

3. Có nên bắt đầu port code hiện tại để bắt đầu sử dụng hàm Lambda không ?

  • Nếu code của bạn mà sử dụng Lambda thì nhìn ngầu phải biết. Anh chị em nào lơ tơ mơ nhìn vô thì thấy khiếp ngay.
  • Và vì lí do Lambda chỉ xuất hiện trên C++ 11, mà C++11 chỉ hỗ trợ biên dịch trên các phiên bản compiler mới, và cũng không phải tất cả các platform đều hỗ trợ hết. Do đó hãy cân nhắc dự án của bạn đang sài compiler có đáp ứng điều kiện hay không và platform bạn đang build ra có nói là full hỗ trợ hay không trước khi port code nhé.

3. Cách khai báo và sử dụng hàm Lambda

  • Để bên code và bên biên dịch hiểu nhau thì mấy anh viết compiler bảo thể này, nếu mà tui đọc được một dòng lệnh mà có cấu trúc thế này thì tui hiểu là anh em đang viết hàm Lambda.
[](){}();

trong đó

[] : khai báo với compile đây là hàm lambda

(): các tham số đầu vào. Bên trong ngoặc này ta có thể đặt các biến như int a, int b ví dụ (int a, int b)

{}: phần định nghĩa của hàm. ví dụ {cout << “hello lambdar”; }

() : gọi hàm, bên trong này ta có thể truyền tham số vào, ví dụ (10, “this is input string”)

ví dụ thế này :

 

[](){printf("Hello Lambda\n");}();
hay thế này :
[](int x){printf("x = %d\n",x);}(10);
 
Nếu muốn trả về gía trị thì cũng có luôn :
 
auto res = [](int a, int b){return a + b;}(10,20);
 
  • Với cú pháp ở trên thì khi hệ thống gọi hàm lambda nó cũng tạo cho nó vùng nhớ stack, vậy để can thiệp biến ở bên ngoài nó thì làm thế nào? Không lẽ lọi đưa đối số đầu vào, hoặc biến bên ngoài chuyển về static, vậy bất tiện quá. Thế nên Lambda có thêm tính năng sau:
 
[=] : Capture by copy  – copy giá trị của biến bên ngoài hàm Lambda, bên trong hàm lamda chỉ được dùng giá trị mà không được thay đổi, nếu thay đổi trình biên dịch sẽ báo lỗi ngay ở compiling time.

[&] : Capture by reference – copy tham chiếu, giống ở trên nhưng được phép thay đổi giá trị, và thoát hàm Lambda thì giá trị được thay đổi theo.

[=]mutable:  Nếu trong hàm lambda muốn thay đổi giá trị mà compiler không báo lỗi thì dùng khai báo này. Tất nhiên thoát khỏi hàm Lambda thì những thay đổi này không còn giá trị.

4. Code ví dụ



int main(int argc, char** argv) {
    int xx = func_sum(10,20);
    [](){printf("Hello Lambda\n");}();
    [](int x){printf("x = %d\n",x);}(10); // Truyen doi so
    auto res = [](int a, int b){return a + b;}(10,20); // Tra ve gia tri, tu dong biet kieu gia tra
    printf("res = %d\n",res);
    // Capture by reference/copy value
    // Reference Capture

    int x =100;
    printf("Gia tri ban dau x = %d\n",x);
    [&](){printf("capture x by reference = %d\n",x); x =200;}();
    printf("Gia tri sau khi chay ham  x = %d\n",x);
    // Copy capture, compiler se bao loi neu trong chuong trinh ghi de gia tri
    int y =100;
    [=](){printf("capture y by copy = %d\n",y);}();
    // Neu van muon thay doi gia tri cua bien  ma khong bao loi thi dung mmutable
    int z =100;
    [=]()mutable{printf("ghi de copy capture = %d\n",z); z =200;}();
    printf("z = %d\n",z);

    return 0;
}