1 語法
Lambdas並不是新概念,在其它語言中已經爛大街了。直接進入主題,先看語法:
[ captures ] ( params ) specifiers exception attr -> ret { body } (1)
[ captures ] ( params ) -> ret { body } (2)
[ captures ] ( params ) { body } (3)
[ captures ] { body } (4)
- captures:捕獲參數。詳細格式見下圖。
格式 | 意義 |
---|---|
[] | 默認不捕獲任何變量 |
[=] | 默認以值捕獲所有變量 |
[&] | 默認以引用捕獲所有變量 |
[x] | 僅以值捕獲x,其它變量不捕獲 |
[&x] | 僅以引用捕獲x,其它變量不捕獲 |
[=, &x] | 默認以值捕獲所有變量,但是x是例外,通過引用捕獲 |
[&, x] | 默認以引用捕獲所有變量,但是x是例外,通過值捕獲 |
[this] | 通過引用捕獲當前對象(其實是復制指針) |
[*this] | 通過傳值方式捕獲當前對象 |
- params:參數列表。
- ret:返回類型。
- body:函數體。
- specifiers:限定符列表。比如mutable。
- exception:異常規定。比如noexcept。
- attr:屬性規定,詳見。
2 使用
Lambdas重在使用,所以下面直接上實例,由淺入深的介紹使用方法。
2.1 打印字符串
- 定義一個匿名函數
[]{
std::cout<< "hello world!" <<std::endl;
}
- 調用匿名函數
[]{
std::cout<< "hello world!" <<std::endl;
}();
- 傳遞匿名函數給一個變量
auto l = []{
std::cout<< "hello world!" <<std::endl;
};
l();
2.2 帶參數列表的匿名函數
auto l = [](const std::string &s){
std::cout<< s <<std::endl;
};
l("hello world!");
2.3 指定返回值類型的匿名函數
[] -> double{
return 42;
}
等價於
[]{
return 42;
}
如果不指定返回類型,C++11也可以自動推斷類型。
2.4 帶捕獲參數的匿名函數
- 捕獲變量值+捕獲變量引用
int x = 0;
int y = 42;
auto f = [x, &y] {
std::cout<<"x:" << x << std::endl;
std::cout<<"y:" << y << std::endl;
++y;
//++x;//Error
};
x = y = 77;
f();
f();
std::cout<< "final y: " << y <<std::endl;
輸出
x:0
y:77
x:0
y:78
final y: 79
- 捕獲所有變量值
int x = 0;
int y = 42;
auto f = [=] {
std::cout<<"x:" << x << std::endl;
std::cout<<"y:" << y << std::endl;
//++y;//Error
//++x;//Error
};
x = y = 77;
f();
f();
std::cout<< "final y: " << y <<std::endl;
輸出
x:0
y:42
x:0
y:42
final y: 77
- 捕獲所有變量引用
int x = 0;
int y = 42;
auto f = [&] {
std::cout<<"x:" << x << std::endl;
std::cout<<"y:" << y << std::endl;
++y;//Error
++x;//Error
};
x = y = 77;
f();
f();
std::cout<< "final x: " << x <<std::endl;
std::cout<< "final y: " << y <<std::endl;
輸出
x:77
y:77
x:78
y:78
final x: 79
final y: 79
2.5 使用匿名函數統計容器中所有元素的值之和
std::vector<int> vec = { 1, 2, 3, 4, 5 };
double total = 0;
//inclucde 'algorithm' for foreach
std::foreach(begin(vec), end(vec),
[&](int x) {
total += x;
});
std::cout<<"total:"<< total <<std::endl;
輸出:
total:15
2.6 使用匿名函數對容器中的元素排序
struct Point{
double x,y;
Point(){
x = (rand() % 10000) - 5000;
y = (rand() % 10000) - 5000;
}
void Print(){
std::cout<<"["<<x<<","<<y<<"]"<<std::endl;
}
};
int count = 10;
std::vector<Point> points;
for( auto i = 0; i < 10 ; i++ ) points.push_back(Point());
cout<<"Unsorted:"<<endl;
for( auto i = 0; i < 10 ; i++ ) points[i].Print();
std::sort(points.begin(), points.end(),
[](const Point& a, const Point& b) -> bool{
return (a.x * a.x) + (a.y * a.y) < (b.x * b.x) + (b.y * b.y);
});
cout<<"Sorted:"<<endl;
for( auto i = 0; i < 10 ; i++ ) points[i].Print();
輸出:
Unsorted:
[4383,-4114]
[-2223,1915]
[2793,3335]
[386,-4508]
[1649,-3579]
[-2638,-4973]
[3690,-4941]
[2763,-1074]
[-4460,-1574]
[4172,736]
Sorted:
[-2223,1915]
[2763,-1074]
[1649,-3579]
[4172,736]
[2793,3335]
[386,-4508]
[-4460,-1574]
[-2638,-4973]
[4383,-4114]
[3690,-4941]
2.7 返回匿名函數類型
//include<functional>
std::function<int(int,int)> returnLambda (){
return [](int x, int y){
return x*y;
};
}
auto lf = returnLambda();
std::cout<< lf(6,7) << std::endl;
2.8 奇怪的捕獲變量作用域
void PerformOperation( function<void()> f ){
f();
}
int main(){
int x = 100;
auto func = [&](){ x++;};
PerformOperation(func);
std::cout<< "x:" << x << std::endl;
return 0;
}
輸出:
x:101