lambda表達式
//c++ 11中的lambda表達式用于定義并建立匿名的函數對象,以簡化程式設計工作。lambda的文法形式如下:
//[函數對象參數](操作符重載函數參數)mutable或exception聲明->傳回值類型{函數體
}
//可以看到,lambda主要分為五個部分:
//[函數對象參數]、(操作符重載函數參數)、mutable或exception聲明、->傳回值類型、{函數體
}。下面分别進行介紹。
//一、[函數對象參數],辨別一個lambda的開始,這部分必須存在,不能省略。函數對象參數是傳遞給編譯器自動生成的函數對象類的構造函數的。
//函數對象參數隻能使用那些到定義lambda為止時lambda所在作用範圍内可見的局部變量(包括lambda所在類的this)。函數對象參數有以下形式:
//1、空。沒有使用任何函數對象參數。
//2、 =。函數體内可以使用lambda所在作用範圍内所有可見的局部變量(包括lambda所在類的this),并且是值傳遞方式(相當于編譯器自動為我們按值傳遞了所有局部變量)。
//3、&。函數體内可以使用lambda所在作用範圍内所有可見的局部變量(包括lambda所在類的this),并且是引用傳遞方式(相當于編譯器自動為我們按引用傳遞了所有局部變量)。
//4、this。函數體内可以使用lambda所在類中的成員變量。
//5、a。将a按值進行傳遞。按值進行傳遞時,函數體内不能修改傳遞進來的a的拷貝,因為預設情況下函數是const的。要修改傳遞進來的a的拷貝,可以添加mutable修飾符。
//6、&a。将a按引用進行傳遞。
//7、a, &b。将a按值進行傳遞,b按引用進行傳遞。
//8、 =,&a,&b。除a和b按引用進行傳遞外,其他參數都按值進行傳遞。
//9、&, a, b。除a和b按值進行傳遞外,其他參數都按引用進行傳遞。
//二、(操作符重載函數參數),辨別重載的()操作符的參數,沒有參數時,這部分可以省略。參數可以通過按值(如:(a,
b))和按引用(如:(&a, &b))兩種方式進行傳遞。
//三、mutable或exception聲明,這部分可以省略。按值傳遞函數對象參數時,加上mutable修飾符後,可以修改按值傳遞進來的拷貝(注意是能修改拷貝,而不是值本身)。
//exception聲明用于指定函數抛出的異常,如抛出整數類型的異常,可以使用throw(int)。
//四、->傳回值類型,辨別函數傳回值的類型,當傳回值為void,或者函數體中隻有一處return的地方(此時編譯器可以自動推斷出傳回值類型)時,這部分可以省略。
//五、{函數體
},辨別函數的實作,這部分不能省略,但函數體可以為空。
案例1:
#include<functional>
#include<iostream>
#include<vector>
#include<algorithm>
usingnamespacestd;
//lambda表達式簡單案例
voidmain()
{
autofun1
= [](){cout <<"hellochina"<<endl;
};
fun1();
autofun2
= [](inta,intb){returna
+b; };
cout
<<fun2(10, 9) <<endl;
std::cin.get();
運作結果:
案例2:
vector<int> myv;
myv.push_back(1);
myv.push_back(2);
myv.push_back(11);
autofun1
= [](intv){ cout
<<v <<endl;
//通過這種方式操作myv中的值
for_each(myv.begin(),myv.end(),fun1);
<<"----------------" <<endl;
//直接寫在内部,下面的v表示傳遞進lambda表達式的參數
for_each(myv.begin(),myv.end(),[](intv)
{
cout
});
案例3:
inta
= 10;
// =知道a的存在,可以引用,隻能讀,不可以寫,引用目前塊語句内部的局部變量
= [=](intv){v
+=a; cout
<<v <<endl; };
//此時a沒有被修改
<<a <<endl;
案例4:
//引用變量a,相當于直接操作a
= [&a](intv){a
= 3; v +=a; cout
//此時a發生變化
案例5:
[](){cout
<<"hellochina"; };//是一個函數指針
<<"hellochina";}();//如果沒有定義名稱,如果想調用lambda表達式,可以直接在lambda表達式的最後面加上()
cin.get();
案例6:
classtest
public:
intnum;
voidadd()
num
= 12;
myv.push_back(10);
myv.push_back(11);
//[]引用this
int x
= 3;
autofun1
= [this,x](intv){cout
<<v+x+this->num
<< endl; };
//=按照副本引用this,還有目前塊語句局部變量,不可以指派,但是可以讀取
//&按照引用的方式操作局部變量,this,可以指派,可以讀取
//副本引用a,[=] [a]
//引用a
[&] [&a]
autofun2
= [&](intv){cout
<<v +x
+this->num
<< endl;x
= 3; };
for_each(this->myv.begin(),this->myv.end(),fun1);
cout
<<"-----------------" <<endl;
for_each(this->myv.begin(),this->myv.end(),fun2);
}
testt;
t.add();
案:7:
//傳回值案例
//double是傳回值類型
= []()->double{cout
<< "hello china" <<endl;return
1; };
//通過decltype(a/b)的方式獲得類型
= [](inta,doubleb)->decltype(a
/ b){cout
<< "hello china" <<endl;returna
/b; };
fun2(1,
2.3);
案例8:
void main()
//mutable使可以改副本了。如果下面的去掉将會報錯
= [a](intv)mutable->double{v
+= a; cout
<<v <<endl;a
= 3;return 3; };
//運作結果還是10
lambada表達式補充
auto
func = []{return 1; };
int
i = func();
cclog("i = %d",
i);
}
//最簡單的lambada表達式是隻要一個中括号和一個大括号
//[]捕獲清單
//{}函數體
//1.捕獲清單,可以放變量名,這裡可以用來傳遞函數體内定義的變量
{
v = 100;
func = [v]{return
v; };
x = func();
//2.捕獲清單,可以捕獲多個變量
p = 100, q = 200;
func = [p, q]{return
p + q; };
s = func();
// 3.捕獲清單,有引用和傳值兩種方式,傳值不可以改變,引用可以改變,并且改變外部的變量值
func = [p, &q]{q++;
return p +
q; };
//4.捕獲清單,可以定義mutable類型的lambada,能改變傳值的捕獲參數,
//但是不能改變外部的變量值
func = [p, q]()mutable{p++;
q++; return
cclog("p = %d,q = %d,s = %d",
p, q,
s);
//5.捕獲清單,可以用=或者&捕獲所有變量,=指傳值,&表示引用
//用&的時候,所有的都可以調用了,[&,p]:表示除了p不能被使用,其它的都可以被使用
func = [&]{
return
p + q;
};
//稍微複雜點的lambda表達式
add = [](int v1,
int v2){return
v1 + v2; };
a = add(1 , 2);
//小括号中的是參數清單,參數清單和捕獲清單差別在于,參數清單的參數由調用方決定,
//捕獲清單由定義方決定,是以更加靈活
//更加複雜的lambada表達是,有傳回值,傳回值一般都省略
//->int表示傳回值是int類型的
int v2)->int{return
//總結:auto func = [](){}
func = [](){};