STL之lambda表示式

2021-09-08 13:52:38 字數 4402 閱讀 1617

我們可以向乙個演算法傳遞任何類別的可呼叫物件。對於乙個物件或乙個表示式,如果可以對其使用呼叫運算子,則稱它為可呼叫的。即,如果e是乙個可呼叫的表示式,則我們可以編寫**e(args),其中args是乙個逗號分隔的乙個或多個引數的列表。

可呼叫物件分別有:1、函式和函式指標;2、過載了函式呼叫運算子的類;3、lambda表示式。

乙個lambda表示式表示乙個可呼叫的**單元。我們可以將其理解為乙個未命名的內聯函式。與任何函式類似,乙個lambda具有乙個返回型別、乙個引數列表和乙個函式體。但與函式不同,lambda可能定義在函式內部。乙個lambda表示式具有如下形式:

[capture list](parameter list) -> return type

其中,capture list(捕獲列表)是乙個lambda所在函式中定義的區域性變數的列表(通常為空);return type、parameter list和function body與任何普通函式一樣,分別表示返回型別、引數列表和函式體。但是,與普通函式不同,lambda必須使用尾置返回來指定返回型別。

我們可以忽略引數列表和返回型別,但必須永遠包含捕獲列表和函式體

auto f =  ;

此例中,我們定義了乙個可呼叫物件f,它不接受引數,返回42.

lambda的呼叫方式與普通函式的呼叫方式相同,都是使用呼叫運算子:

cout << f() << endl;  //

列印42

在lambda中忽略括號和引數列表等價於指定乙個空引數列表。在此例中,當呼叫f時,引數列表是空的。如果忽略返回型別,lambda根據函式體中的**推斷出返回型別。如果函式體只是乙個return語句,則返回型別從返回的表示式的型別推斷而來。否則,返回型別為void。

與普通函式不同,lambda不能有預設引數。因此,乙個lambda呼叫的實參數目永遠與形引數目相等。

例如:

(const

string &a, const

string &b)

空捕獲列表表明此lambda不使用它所在函式中的任何區域性變數。如下所示,可以使用此lambda來呼叫stable_sort:

// 按長度排序,長度相同的單詞維持字典序

stable_sort(words.begin(), words.end(),

(const

string &a, const

string &b)

);

當stable_sort需要比較兩個元素時,它就會呼叫給定的這個表示式。

接下來我們需要編寫乙個可傳遞給find_if的可呼叫表示式。我們希望這個表示式能將輸入序列中每個string的長度與biggies函式中的sz引數的值進行比較。

在本例中,我們的lambda會捕獲sz,並只有單一的string引數。其函式體會將string的大小與捕獲的sz的值進行比較:

[sz](const

string &a)

;

ps:捕獲列表只用於區域性非static變數,lambda可以直接使用區域性static變數和在它所在函式之外宣告的名字。

呼叫範例:

當定義乙個lambda時,編譯器生成乙個與lambda對應的新的(未命名的)類型別。

類似引數傳遞,變數的捕獲方式也可以是值或引用。當lambda採用值捕獲的時候,前提條件為變數可以拷貝,**獲的變數的值是在lambda建立時拷貝,而不是呼叫時拷貝:

void

fcn1()

; v1 = 0

; auto j = f(); //

j為42,f儲存了我們建立它時v1的拷貝

}

我們定義lambda時可以採用引用方式捕獲變數。例如:

void

fcn2()

; v1 = 0

; auto j = f2(); //

j為0,f2儲存v1的引用,而非拷貝

}

除了顯示列出我們希望使用的來自所在函式的變數之外,還可以讓編譯器根據lambda體重的**來推斷我們要使用哪些變數。為了指示編譯器推斷捕獲列表,應在捕獲列表中寫乙個&或=。&告訴編譯器採用捕獲引用方式,=則表示採用值捕獲方式。例如:

//

sz為隱式捕獲,值捕獲方式

wc =find_if(words.begin(), words.end(),

[=](const

string &s)

);

如果我們希望對一部分變數採用值捕獲,對其他變數採用引用捕獲,可以混合使用隱式捕獲和顯式捕獲:

1

void biggies(vertor &words,

23 vertor::size_type sz,

45 ostream &os = cout, char c =『 『)67

);14

15//

os顯式捕獲,引用捕獲方式;c隱式捕獲,值捕獲方式

1617

for_each(words.begin(), words.end(),

1819 [=, &os](const

string &s) );

2021 }

當我們混合使用隱式捕獲和顯式捕獲時,捕獲列表中的第乙個元素必須是乙個&或=.

預設情況下,對於乙個值被拷貝的變數,lambda不會改變其值。如果我們希望能改變乙個**獲的變數的值,就必須在引數列表首加上關鍵字mutable。

1

void

fcn3()23

;89 v1 = 0;10

11 auto j = f(); //

j為42

1213 }

當我們需要為乙個lambda定義返回型別時,必須使用尾置返回型別:

1

transform(vi.begin(), vi.end(), vi.begin(),

23 (int i) - > int

45 );

對於那種只在一兩個地方使用的簡單操作,lambda表示式是最有用的。如果我們需要在很多地方使用相同的操作,通常應該定義乙個函式,而不是多次編寫相同的lambda表示式。

但是,對於捕獲區域性變數的lambda,用函式來替代它就不是那麼容易了。例如我們用在find_if呼叫中的lambda比較乙個string和乙個給定大小。我們可以很容易地編寫乙個完成同樣工作的函式:

1

bool check_size(const

string &s, string

::size_type sz)23

我們可以額解決向check_size傳遞乙個長度引數的問題,方法是使用乙個新的名為bind的標準庫函式,它定義在標頭檔案functional中。可以將bind函式看作乙個通用的函式介面卡,它接受乙個可呼叫物件,生成乙個新的可呼叫物件來「適應」原物件的引數列表。

呼叫bind的一般形式為:

auto newcallable = bind(callable, arg_list);

其中,newcallable本身是乙個可呼叫物件,arg_list是乙個逗號分隔的引數列表,對應給定的callable的引數。即,當我們呼叫newcallable時,newcallable會呼叫callable,並傳遞給它arg_list中的引數。

作為乙個簡單的例子,我們將使用bind生成乙個呼叫check_size的物件,如下所示,它用乙個定值作為其大小引數來呼叫check_size:

1

//chenck6是乙個可呼叫物件,接受乙個string型別的引數23

//並用此string和值6來呼叫check_size

45 auto check6 = bind(check_size, _1, 6);

呼叫check6必須傳遞給它乙個string型別的引數,check6會將此引數傳遞給check_size。

string s =「hello」;

bool b1 = check6(s); //

check6(s)會呼叫check_size(s,6)

使用bind,我們可以將原來基於lambda的find_if呼叫:

auto wc =find_if(words.begin(), words.end(),

[sz](

const

string &a)

替換為如下使用check_size的版本:

auto wc = find_if(words.begin(), words.end(), bind(check_size, _1, sz));

參考:《c++ primer》

lambda表示式 lambda表示式

1.概述 c 11 中的 lambda 表示式用於定義並建立匿名的函式物件,以簡化程式設計工作。lambda 的語法形式如下 函式物件引數 操作符過載函式引數 mutable 或 exception 宣告 返回值型別可以看到,lambda 主要分為五個部分 函式物件引數 操作符過載函式引數 muta...

Lambda表示式和Lambda表示式樹

原版來自 linq學習筆記之二 lambda表示式和lambda表示式樹 lambda 表示式 lambda expressions 是linq實現的另一特性。lambda表示式的作用就是使用使用函式式語法,將方法實現關聯到委託例項。在使用查詢表示式 query expressions 時,查詢表示...

python之lambda表示式

lambda的主體是乙個表示式,而不是乙個 塊。僅僅能在lambda表示式中封裝有限的邏輯進去。lambda表示式是起到乙個函式速寫的作用。允許在 內嵌入乙個函式的定義。事例 建立匿名函式 g lambda x 2 x 1 冒號前面是變數,冒號後面是表示式 g 5 11 g lambda x,y x...