C++11 帶來的新特性 (4)—— 匿名函數(Lambdas)

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重在使用,因此下面直接上實例,由淺入深的介紹使用方法。this

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也能夠自動推斷類型。code

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;

輸出orm

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;

輸出:ci

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
相關文章
相關標籤/搜索