Home Item 14 - 初始化捕獲(initializer capture)(中文)
Post
Cancel

Item 14 - 初始化捕獲(initializer capture)(中文)

初始化捕獲

上一篇講到 c++ 11 可以支援 Lambda 捕獲變量,看 code 回顧一下,而且改寫一下故意把變數名稱寫的很長。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

int main() {
    int x_thisIsAnExtremelyLongVariableName = 10;
    int y_thisIsAnExtremelyLongVariableName = 20;

    auto addXY = [x_thisIsAnExtremelyLongVariableName, y_thisIsAnExtremelyLongVariableName]() -> int {
        return x_thisIsAnExtremelyLongVariableName + y_thisIsAnExtremelyLongVariableName;
    };

    std::cout << "x_thisIsAnExtremelyLongVariableName + y_thisIsAnExtremelyLongVariableName = " << addXY() << std::endl;

    return 0;
}

這個限制就是當我們在捕獲變量時,只能使用相同的變數名稱去補獲。 (當變數名稱很奇怪時,會在你的 Lambda function 中出現) 當然這不是 c++ 14 要改善的主要原因。

C++14 引入了一項名為初始化捕獲(initializer capture)的功能,這使得在 lambda 表達式中捕獲變量變得更加靈活。它允許你在捕獲列表中進行變量的初始化,這對於需要在 lambda 表達式中使用臨時變量或計算值時特別有用。

使用時機

有主要以下 4 種:

計算複雜表達式

當你需要在 lambda 表達式中使用複雜的計算結果時,可以使用初始化捕獲來簡化代碼。

1
2
3
4
5
int a = 27;
int b = 37;
auto lambda = [sum = a * b + 3](int x) {
    return sum + x;
};

捕獲臨時對象

當你需要在 lambda 表達式中使用臨時對象(如動態分配的內存、臨時字符串等)時,可以使用初始化捕獲來確保這些對象的生命週期覆蓋 lambda 表達式的使用範圍。

以下使用 std::move ,若不太熟悉的人,可以參考此篇

1
2
3
4
5
6
auto ptr = std::make_unique<int>(48);
auto lambda = [p = std::move(ptr)]() {
    std::cout << *p << std::endl;
};
lambda();

重命名變量

如果你想在 lambda 表達式中使用不同的變量名稱,可以通過初始化捕獲來實現變量的重命名。

拿開頭的例子舉例

1
2
3
4
int x_thisIsAnExtremelyLongVariableName = 100;
auto lambda = [x = x_thisIsAnExtremelyLongVariableName](int y) {
    return x + y;
};

捕獲參考

雖然通常可以通過 [&] 捕獲所有外部變量的引用,但有時你需要捕獲某些特定變量的引用,這時初始化捕獲也能派上用場。

1
2
3
4
5
6
int a = 45;
auto lambda = [&ref_a = a]() {
    ref_a += 17;
};
lambda();
std::cout << "a: " << a << std::endl;

Desktop View

這些情境展示了初始化捕獲在不同場景中的應用,提供了更靈活和簡潔的編程方式。

☝ツ☝

This post is licensed under CC BY 4.0 by the author.

👈 ツ 👍

Item 14 - initializer capture (English)

Item 16 - fold expressions (English)