iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0

不少 C++ 的教學文都會拿 Lambda 表達式(Lambda expression)當範例,這是從 C++ 11 標準中開始出現的寫法,本篇就來快速看過什麼是 Lambda 表達式。

語法

Lambda 表達式的語法如下:

[capture](parameters) -> return_type {
    // function body
}

以下一一介紹各部位功能:

  • [capture]:捕獲,這是 Lambda 表達式最特別的地方,可以從同一作用域中抓取區域變數,而不必每個變數都透過參數抓進來,稍後將詳細說明。
  • (parameters):參數,就跟一般函數的參數一樣。
  • return_type { // function body }:這邊也跟一般函數一樣,但回傳的型別 return type 通常不寫。

舉例來說:

[x](int y) -> int { return x + y; };

表示捕獲 x、拿到參數 y,函數本體是 x + y,函數回傳的型別是 int

回傳型別通常由編譯器自行決定,因此可省略,寫成:

[x](int y) { return x + y; };

運算結果賦值到變數

而假設該 Lambda 函數運算的結果要賦值於一變數,該變數型別通常寫成 auto,表示由編譯器自己判斷該變數型別,而非由我們手工指定,例如如果要賦值於變數 f,則寫成:

auto f = [x](int y) -> int { return x + y; };
// 或者
auto f = [x](int y) { return x + y; };

何謂「捕獲」

Lambda 表達式可以在同一作用域「捕獲(capture)」變數,表示不用把變數寫成參數,表達式也能抓到,例如:

#include <iostream>
using namespace std;

int main() {
    int x = 10;

    auto f = [x](int y) {
        return x + y;
    };

    cout << "x = " << x << endl;
    cout << "f(3) => x = 10, y = 3, result = " << f(3) << endl;
    cout << "f(7) => x = 10, y = 7, result = " << f(7) << endl;

    return 0;
}

這裡的 Lambda 表達式跟 x 在同一作用域 main() 中,因此 [x] 可直接捕獲 x,不用在呼叫 f 這個變數代表的 Lambda 表達式時,另外把 x 當參數傳進去。

因此在 f(3)f(7) 中,雖然都只有吃參數 y(確切的值分別為 37),但函數裡面一樣可以拿 x = 10 這個變數值去運算。

「捕獲」的類別

事實上,捕獲的方式有很多種,包含:

  • []:完全不抓。
  • [=]:全部都傳值(by value),因此抓到的都是副本,變數改變不影響捕獲的值;上面的範例就是用這種方式。
  • [&]:全部都傳參考(by reference),因此抓到的是變數本身,變數改變會影響捕獲的值。

以下範例對照:

// 用值捕獲
int x = 10;

auto f = [=]() {
    cout << x << endl;  // 這裡的 x 是副本
};

x = 99; // 這裡重新賦值為 99 不影響 f 捕獲
f();    // 輸出依然為 10
// 用參考捕獲
int x = 10;

auto f = [&]() {
    cout << x << endl; // 這裡的 x 是上面的 `int x`
};

x = 99; // 這裡重新賦值改到的 x 會影響 f 捕獲
f();    // 輸出為 99

兩者還可以混用,例如:

  • [x, &y]:x 用值捕獲、y 用參考捕獲。
  • [=, &y]:y 用參考捕獲,其他變數都由值捕獲。
  • [&, x]:x 用值捕獲,其他變數都用參考捕獲。

mutable 改副本

在捕獲副本時,副本本身的值是不能在 Lambda 表達式修改的,例如:

int x = 10;

auto f = [x]() {
    x = 20;
};

這樣會報錯,要改成:

int x = 10;

auto f = [x]() mutable {
    x = 20;      // 改變副本的值
    cout << "x in f is " << x << endl;
};

f();

cout << "x out of f is " << x << endl;

這時 f 裡面的副本就可以被重新賦值為 20,但原本的變數 x 的值依然為 10,執行結果如下:

x in f is 20
x out of f is 10

參考資料

  1. Lambda Expression in C++ (GeeksforGeeks)
  2. Lambda Capture Clause in C++ (GeeksforGeeks)
  3. C++11 Lambda Expression 語法教學與範例

上一篇
Day 12 - 用位元運算做整數加法
下一篇
Day 14 - 中斷
系列文
韌體工程師的不只 0x10 個問題19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言