標籤:tab 檔案 div out lambda color 推斷 socket ram
1.一個lambda運算式表示一個可調用的代碼單元,可以理解為一個未命名的內嵌函式,但是與函數不同,lambda運算式可能定義在函數內部。其形式如下:
[capture list] (parameter list) -> return type { function body }
- capture list 是一個lambda所在函數中定義的局部變數的列表(通常為空白)
- return type, parameter list 和 function body與任何普通函數一樣,分別表示傳回型別,參數列表和函數體
- lambda必須使用尾置返回
- 我們可以忽略參數列表和傳回型別,但必須永遠包含捕獲列表和函數體
- 如果忽略傳回型別,lambda會從函數體推斷出傳回型別。
- 如果lambda的函數體包含任何單一return語句之外的內容,且未指定傳回型別,則返回void
- 捕獲列表只用於局部非static變數,lambda可以直接使用局部static變數和在它所在函數之外聲明的名字。
void test(){ int i = 1; int j = 2; auto f = [i, j](int base) -> int { return base + i + j; }; // i,j必須在捕獲列表裡面,這裡的傳回型別int其實可以省略 int k = f(0); // k的結果為3}
2.當定義一個lambda時,編譯器產生一個與lambda對應的新的(未命名的)類類型。預設情況下這個類都包含一個對於該lambda所捕獲的變數的資料成員。類似任何普通類的資料成員,lambda的資料成員也在lambda對象建立時被初始化。
3.與傳值參數類似,採用值捕獲的前提是變數可以拷貝,與參數不同,被捕獲的變數的值是在lambda建立時拷貝,而不是調用時拷貝。
void test(){ int i = 10; auto f = [i] {return i + 1; }; // 此時i的值就已經被拷貝了 int j = f();}
4.當以引用方式捕獲一個變數時,必須保證在lambda執行時變數是存在的。
void test(){ int i = 10; auto f = [&i] {return ++i; }; int j = f(); // 此時i等於11}
5.在捕獲列表中寫一個 &或= 可以告訴編譯器我們想採用值捕獲還是引用捕獲,這種方法叫做隱式捕獲。
void test(){ int i = 10; auto f = [&] {return ++i; }; // 採用引用捕獲 int j = f(); }
6.我們也可以混合使用值捕獲或者引用捕獲。當使用混合方式的時候,顯示捕獲的方式不可以與隱式捕獲的方式相同。
void test(){ int i = 10; int j = 9; auto f = [=, &i] {i++; return i + j; }; // i採用引用捕獲,其他採用值捕獲 int k = f(); // k等於20}
7.預設情況下,對於一個值被拷貝的變數,lambda不會改變其值,如果我們希望能改變一個被捕獲的變數的值,就必須在參數列表首加上mutable。
void test(){ int i = 10; auto f = [i] (){return ++i; }; // 錯誤,不可以改變i的值 auto f1 = [i] () mutable {return ++i; }; // 正確}
8.bind函數(標頭檔 functional中)可以看作一個通用的函數適配器,它接受一個可調用對象,產生一個新的可調用對象來適應原對象的參數列表。調用bind的一般形式為:
auto newCallable = bind(callable, arg);
void test(int i, int j){ std::cout << i - j << std::endl;}auto test0 = std::bind(test, 5, 1);test0(); // 結果4auto test1 = std::bind(test, std::placeholders::_1, 5, std::placeholders::_2, 1); // 錯誤,不可以這麼寫test1(); auto test2 = std::bind(test, std::placeholders::_1, 5);test2(1); // 結果-4auto test3 = std::bind(test, std::placeholders::_1, std::placeholders::_2);test3(3, 2); // 結果1auto test4 = std::bind(test, std::placeholders::_2, std::placeholders::_1); // 參數順序可以重排test4(3, 2); // 結果-1auto test5 = std::bind(test, 1, std::placeholders::_1); // 注意這個預留位置占的是test5()的參數位置,而不是test()的test5(5); // 結果-4
以上代碼請注意命名空間,否則會和socket的bind函數產生二義性。
9.如果我們想綁定的參數無法拷貝,或者我們想引用時應該使用ref函數。
void test(int& i, int j){ std::cout << i - j << std::endl;}int i = 5;auto test0 = std::bind(test, std::ref(i), 1);test0(); // 結果4
C++ Primer 筆記——lambda運算式