banner
Matrix

Matrix

Abyss
email
github

微不足道的C++ - lambda

lambda 表達式在 C++11 之後的版本中是一種定義匿名函數的簡潔語法。在一些長環境下,例如 STL 算法和異步操作,使用 lambda 作為回調函數非常自然和方便,並且 lambda 和 C++ 的函數式編程特性非常契合。

基本語法#

一個完整的 lambda 表達式語法如下:

[caputreList](paramList) mutable throw() -> returnType {
  // do something..
}

捕獲列表#

lambda 以一個中括號的捕獲列表開始,捕獲列表用來定義哪些外部變量可以被 lambda 表達式使用,以及如何使用(傳值,引用)。

捕獲列表可以為空,表示 lambda 不使用閉包之外的變量,但中括號不可省略。

無論是傳值還是引用方式,都可以使用默認的捕獲方式,在默認捕獲方式下,編譯器會自動分析 lambda 需要捕獲哪些外部變量。默認傳值捕獲方式和默認的引用捕獲方式可以混用,具體用法如下:

[=] // 默認傳值捕獲
[&] // 默認引用捕獲
[&, factor] // 除factor傳值捕獲外,其他變量使用引用捕獲。
[=. factor] // 除factor引用捕獲外,其他變量使用傳值捕獲。

捕獲列表不允許重複聲明,這種重複包括捕獲方式重複和變量重複:

[&, &factor] // 錯誤, & 已經聲明了默認的捕獲方式. &factor 重複
[=, factor] // 同上
[factor, factor] // 錯誤,變量重複

自動捕獲提供了更方便的捕獲機制,但是可能會導致無意間捕獲不需要的變量,可能會到之前在的內存使用增加或引入性能問題。

傳值還是引用捕獲的選擇一般需要通過特定的場景來選擇,一般來說,傳值還是引用的捕獲方式選擇和正常函數傳參方式的規則差不多。

捕獲列表同樣可以使用可變參數模板:

[arg...]

在類成員函數體中使用 lambda 表達式時,需要把this指針顯式捕獲,以提供對類成員函數和數據的訪問權限。

[this, filter]

C++14 中引入了一種新的默認捕獲方式,可以在捕獲字句中引入並初始化新的變量,而無需把這些變量放在閉包內,這對於一些需要考慮作用域和聲明周期的變量非常有用:

auto p = make_uniqure<T>(factor);

auto _lambda = [ptr = move(p)]{}

參數列表#

lambda 的參數列表行為等大多數方面類似於標準函數的參數列表。

捕獲列表和參數列表在某種意義上都可以用來給閉包提供變量,但捕獲列表適用於哪些在定義 lambda 時就已知且在後續調用中不會改變的變量。

捕獲列表適用於在整個 lambda 的聲明週期中保持不變的變量,參數列表適用於在每次調用 lambda 時都不同的變量。

std::vector<int> num = {1,2,3,4};
int fixedValue = 10;

std::for_each(num.begin(). num.end(), [fixedValue](int &x){x += fixedValue;});

在參數列表中,如果參數類型是泛型的,則使用 auto 告知編譯器創建模板:

[](auto factor)

mutable#

一般地,lambda 的函數調用時 const-by-value 的,但是加入 mutable 規範後,閉包可以修改值捕獲的變量:

異常#

throw()用來指示 lambda 拋出異常,可以省略,也可以使用 noexcept 指示不拋出異常:

[]() noexcpet {}
[]() throw() {}
[]() {}

返回類型#

在 lambda 中 返回類型指示可以省略,由編譯器自動推斷,但也有例外:

// C++11以及以前,某些編譯器
[](int i){
  if (i < 0){
    return i;
  }
  else{
    return -i;
  }
} // 錯誤,推斷類型為void

這是由於閉包的operator()推斷規則:

如果主體只包含 return 一個表達式,返回類型為表達式類型,否則返回類型為 void。 (C++ 14 之前)。

lambda 體#

基本行為和一般函數一致。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。