C++11/14學習(八)Lambda表達式

Lambda 表達式是 C++11 中最重要的新特性之一。類似匿名函數,當需要一個函數但是又不想費力去命名時使用。
這樣的場景其實有很多,所以匿名函數幾乎是現代編程語言的標配。

Lambda 表達式基礎

Lambda 表達式的基本語法如下:

[捕獲列表](參數列表) mutable(可選)異常屬性 -> 返回類型 {
	// 函數體
}

捕獲列表,可以理解爲參數的一種類型。
lambda 表達式內部函數體在默認情況下是不能夠使用函數體外部的變量的,這時候捕獲列表可以起到傳遞外部數據的作用。
根據傳遞的行爲,捕獲列表也分爲以下幾種:

  1. 值捕獲
    值捕獲的前提是變量可以拷貝,被捕獲的變量在 lambda 表達式被創建時拷貝,而非調用時才拷貝:
void learn_lambda_func_1() {
	int value_1 = 1;
	auto copy_value_1 = [value_1] {
		return value_1;
	};
	value_1 = 100;
	auto stored_value_1 = copy_value_1();
	// 這時, stored_value_1 == 1, 而 value_1 == 100.
	// 因爲 copy_value_1 在創建時就保存了一份 value_1 的拷貝
}
  1. 引用捕獲
    引用捕獲保存的是引用,值會發生變化:
void learn_lambda_func_2() {
	int value_2 = 1;
	auto copy_value_2 = [&value_2] {
		return value_2;
	};
	value_2 = 100;
	auto stored_value_2 = copy_value_2();
	// 這時, stored_value_2 == 100, value_1 == 100.
	// 因爲 copy_value_2 保存的是引用
}
  1. 隱式捕獲
    手動書寫捕獲列表有時候是非常複雜的,這種機械性的工作可以交給編譯器來處理。
    可以在捕獲列表中寫一個 & 或 = 向編譯器聲明採用 引用捕獲或者值捕獲。
    捕獲列表的最常用的四種形式可以是:
  • [] 空捕獲列表
  • [name1, name2, …] 捕獲一系列變量
  • [&] 引用捕獲, 讓編譯器自行推導捕獲列表
  • [=] 值捕獲, 讓編譯器執行推導應用列表
  1. 表達式捕獲(C++14)
    這部分內容需要了解後面馬上要提到的右值引用以及智能指針
    上面提到的值捕獲、引用捕獲都是已經在外層作用域聲明的變量,因此這些捕獲方式捕獲的均爲左值,而不能捕獲右值。
    C++14允許捕獲的成員用任意的表達式進行初始化。
    被聲明的捕獲變量類型會根據表達式進行判斷,判斷方式與使用auto 本質上是相同的:
#include <iostream>
#include <utility>
int main() {
	auto important = std::make_unique<int>(1);
	auto add = [v1 = 1, v2 = std::move(important)](int x, int y)
		-> int {
		return x + y + v1 + (*v2);
	};
	std::cout << add(3, 4) << std::endl;
	return 0;
}

在上面的代碼中, important 是一個獨佔指針,是不能夠被捕獲到的,這時候我們需要將其轉移爲右值,在表達式中初始化。

泛型 Lambda(C++14)

Lambda 表達式並不是普通函數,所以 Lambda 表達式並不能夠模板化。
這就爲我們造成了一定程度上的麻煩:參數表不能夠泛化,必須明確參數表類型。
從 C++14 開始,Lambda 函數的形式參數可以使用 auto 關鍵字來產生意義上的泛型:

auto add = [](auto x, auto y) {
	return x + y;
};
add(1, 2);
add(1.1, 2.2);
發佈了67 篇原創文章 · 獲贊 11 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章