lambda表達式
:也就是匿名函數(shù),也可以稱作閉包(Closure),字面意義是沒有名字的函數(shù)。它可以很方便地讓我們隨手定義函數(shù),并把函數(shù)當做參數(shù),給其他函數(shù)調(diào)用。這樣的代碼寫起來很簡潔,讀起來也直觀。
舉例1:對序列{0,11,3,19,22,7,1,5}
如何從小到大排序呢?,可以通過定義匿名函數(shù)的方式實現(xiàn)。
#include
#include#includeusing namespace std;
int main()
{vectorvec {0,11,3,19,22,7,1,5};
auto f =[](int a, int b)
{return ab從大到小排序
};
sort(vec.begin(),vec.end(),f);
}
[ ]
, 里面可以傳入捕獲變量的形式或者為空()
包起來的參數(shù)列表->
并跟著返回值類型
body
舉例2:
auto f = [](int a, int b) ->int {return a+b;
};
cout<< f(1,2)<
>>3
[ ]
里面是空的,表示不捕獲外圍的變量返回值int 是可以忽略的
,因為編譯器可通過return a+b
以及參數(shù)類型,自行推斷它的返回類型。所以可以等價于如下:auto f = [](int a, int b){return a+b;
};
cout<< f(1,2)<
一般情況下,不指定 lambda 表達式的返回值,編譯器會根據(jù) return 語句自動推導返回值的類型,但需要注意的是 labmda表達式不能通過列表初始化自動推導出返回值類型。
// ok,可以自動推導出返回值類型
auto f = [](int i)
{return i;
}
// error,不能推導出返回值類型
auto f1 = []()
{return {1, 2}; // 基于列表初始化推導返回值,錯誤
}
2.1 變量捕獲(Capture Cluse)[ ]
中可以指定一些外圍的變量,這樣在匿名函數(shù)內(nèi)部就可以訪問這些變量。如果是空的[]
表示不捕獲任何變量。&
,表示按引用捕獲,可以修改
外部變量的值。如果不加引用符號&
,就表示按值捕獲,不能修改外圍變量的值舉例3:
int N =100, M =10;
auto g = [N,&M](int i)
{M=20;
return N*i;
}
cout<< g(10)<< endl;
cout<< M<< endl;
輸出
>>1000 // 100*10
>>20 // 匿名函數(shù)內(nèi)部M賦值為20
注:這里N是沒有加&
號,只能訪問,不能修改。如果嘗試給N
賦值編譯器會報錯
按引用捕獲
:如果捕獲的語句只有引用符號:[&]
,表示所有的變量都按引用捕獲,即可以修改外圍變量的值。
按值捕獲: 如果捕獲語句為[=]
, 表示所有變量都按值捕獲。
可以單獨指定一些變量按值捕獲,其他變量都按引用捕獲。[&,=N]
,這種寫法表示按值捕獲變量N
,其他變量按引用捕獲。
可以用this
捕獲當前實例的指針,在c++17之后,還可以用[*this]
按值捕獲該實例。
舉例
#include#includeusing namespace std;
class Test
{public:
void output(int x, int y)
{auto x1 = [] {return m_number; }; // error
auto x2 = [=] {return m_number + x + y; }; // ok
auto x3 = [&] {return m_number + x + y; }; // ok
auto x4 = [this] {return m_number; }; // ok
auto x5 = [this] {return m_number + x + y; }; // error
auto x6 = [this, x, y] {return m_number + x + y; }; // ok
auto x7 = [this] {return m_number++; }; // ok
}
int m_number = 100;
};
int main(void)
{int a = 10, b = 20;
auto f1 = [] {return a; }; // error
auto f2 = [&] {return a++; }; // ok
auto f3 = [=] {return a; }; // ok
auto f4 = [=] {return a++; }; // error
auto f5 = [a] {return a + b; }; // error
auto f6 = [a, &b] {return a + (b++); }; // ok
auto f7 = [=, &b] {return a + (b++); }; // ok
return 0;
}
2.2 使用mutable修改按值捕獲的外部變量在匿名函數(shù)內(nèi)部,需要通過 lambda 表達式的捕獲列表控制如何捕獲外部變量,以及訪問哪些變量。默認狀態(tài)下 lambda 表達式無法修改通過復制方式捕獲外部變量,如果希望修改這些外部變量,需要通過引用的方式進行捕獲。
使用 lambda 表達式捕獲列表捕獲外部變量,如果希望去修改按值捕獲
的外部變量,那么應該如何處理呢?這就需要使用mutable
選項,被mutable修改是lambda表達式就算沒有參數(shù)也要寫明參數(shù)列
表,并且可以去掉按值捕獲的外部變量的只讀(const)屬性。
int a = 0;
auto f1 = [=] {return a++; }; // error, 按值捕獲外部變量, a是只讀的
auto f2 = [=]()mutable {return a++; }; // ok
最后再剖析一下為什么通過值拷貝的方式捕獲的外部變量是只讀的:
mutable
選項的作用就在于取消 operator () 的 const 屬性
。
因為 lambda 表達式在 C++ 中會被看做是一個仿函數(shù),因此可以使用std::function和std::bind來存儲和操作lambda表達式:
#include#includeusing namespace std;
int main(void)
{// 包裝可調(diào)用函數(shù)
std::functionf1 = [](int a) {return a; };
// 綁定可調(diào)用函數(shù)
std::functionf2 = bind([](int a) {return a; }, placeholders::_1);
// 函數(shù)調(diào)用
cout<< f1(100)<< endl;
cout<< f2(200)<< endl;
return 0;
}
對于沒有捕獲
任何變量
的 lambda 表達式,還可以轉(zhuǎn)換
成一個普通的函數(shù)指針
:
using func_ptr = int(*)(int);
// 沒有捕獲任何外部變量的匿名函數(shù)
func_ptr f = [](int a)
{return a;
};
// 函數(shù)調(diào)用
f(1314);
2.2 其他特性(c++14后)支持在捕獲語句中定義新變量
在c++14之后,可以在捕獲語句中定義新的變量,并且初始化,這些變量無需出現(xiàn)在匿名函數(shù)外圍環(huán)境中
void foo()
{int N=100,M=10;
auto g = [N,&M,K=5](int i)
{M = 20;
cout<< K<< endl;
return N*i;
};
cout<
在匿名函數(shù)中,引入了一個新的變量K
,并且給它賦值5,然后再函數(shù)主體中打印它
參數(shù)類別支持auto類型[](auto a, auto b) {return a+b;}
在c++14新增的功能,參數(shù)列表支持auto類型,這讓匿名函數(shù)變得更通用,這樣只要支出加號類型的變量都可以利用該匿名函數(shù)。
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧