什麼是 lambda 表示式
一個 lambda 表示式提供一個簡明的方式來建立簡單的功能的物件。lambda 表示式是一個 prvalue,其結果物件稱為閉包物件 ,其行為類似於函式物件。
“lambda 表達”這個名字起源於 lambda 演算 ,這是一種數學形式主義,由 Alonzo Church 於 20 世紀 30 年代發明,旨在研究邏輯和可計算性問題。Lambda 演算是 LISP的基礎, LISP是一種函數語言程式設計語言。與 lambda 演算和 LISP 相比,C++ lambda 表示式共享未命名的屬性,並從周圍的上下文中捕獲變數,但它們缺乏操作和返回函式的能力。
lambda 表示式通常用作帶有可呼叫物件的函式的引數。這可能比建立一個命名函式更簡單,該函式僅在作為引數傳遞時使用。在這種情況下,lambda 表示式通常是首選,因為它們允許內聯定義函式物件。
lambda 通常由三部分組成:捕獲列表 []
,可選引數列表 ()
和 body {}
,所有這些都可以為空:
[](){} // An empty lambda, which does and returns nothing
捕獲列表
[]
是捕獲列表。預設情況下,lambda 無法訪問封閉範圍的變數。捕獲變數使其可以在 lambda 中訪問,可以是副本, 也可以是引用 。捕獲的變數成為 lambda 的一部分; 與函式引數相比,它們在呼叫 lambda 時不必傳遞。
int a = 0; // Define an integer variable
auto f = []() { return a*9; }; // Error: 'a' cannot be accessed
auto f = [a]() { return a*9; }; // OK, 'a' is "captured" by value
auto f = [&a]() { return a++; }; // OK, 'a' is "captured" by reference
// Note: It is the responsibility of the programmer
// to ensure that a is not destroyed before the
// lambda is called.
auto b = f(); // Call the lambda function. a is taken from the capture list and not passed here.
引數列表
()
是引數列表,與常規函式幾乎相同。如果 lambda 不帶引數,則可以省略這些括號(除非你需要宣告 lambda mutable
)。這兩個 lambdas 是等價的:
auto call_foo = [x](){ x.foo(); };
auto call_foo2 = [x]{ x.foo(); };
Version >= C++ 14
引數列表可以使用佔位符型別 auto
而不是實際型別。通過這樣做,此引數的行為類似於函式模板的模板引數。當你想要在通用程式碼中對向量進行排序時,以下 lambdas 是等效的:
auto sort_cpp11 = [](std::vector<T>::const_reference lhs, std::vector<T>::const_reference rhs) { return lhs < rhs; };
auto sort_cpp14 = [](const auto &lhs, const auto &rhs) { return lhs < rhs; };
功能體
{}
是正文,與常規函式相同。
叫一個 lambda
lambda 表示式的結果物件是一個閉包 ,可以使用 operator()
呼叫(與其他函式物件一樣):
int multiplier = 5;
auto timesFive = [multiplier](int a) { return a * multiplier; };
std::out << timesFive(2); // Prints 10
multiplier = 15;
std::out << timesFive(2); // Still prints 2*5 == 10
退貨型別
預設情況下,推匯出 lambda 表示式的返回型別。
[](){ return true; };
在這種情況下,返回型別是 bool
。
你還可以使用以下語法手動指定返回型別:
[]() -> bool { return true; };
可變的 Lambda
預設情況下,lambda 中的值捕獲的物件是不可變的。這是因為生成的閉包物件的 operator()
預設為 const
。
auto func = [c = 0](){++c; std::cout << c;}; // fails to compile because ++c
// tries to mutate the state of
// the lambda.
使用關鍵字 mutable
可以允許修改,這使得更近的物件的 operator()
非 const
:
auto func = [c = 0]() mutable {++c; std::cout << c;};
如果與返回型別一起使用,mutable
就會出現在它之前。
auto func = [c = 0]() mutable -> int {++c; std::cout << c; return c;};
一個例子來說明 lambda 的有用性
在 C++ 11 之前:
Version < C++ 11
// Generic functor used for comparison
struct islessthan
{
islessthan(int threshold) : _threshold(threshold) {}
bool operator()(int value) const
{
return value < _threshold;
}
private:
int _threshold;
};
// Declare a vector
const int arr[] = { 1, 2, 3, 4, 5 };
std::vector<int> vec(arr, arr+5);
// Find a number that's less than a given input (assume this would have been function input)
int threshold = 10;
std::vector<int>::iterator it = std::find_if(vec.begin(), vec.end(), islessthan(threshold));
從 C++ 11 開始:
Version >= C++ 11
// Declare a vector
std::vector<int> vec{ 1, 2, 3, 4, 5 };
// Find a number that's less than a given input (assume this would have been function input)
int threshold = 10;
auto it = std::find_if(vec.begin(), vec.end(), [threshold](int value) { return value < threshold; });