C++11 带来的新特性 (4)—— 匿名函数(Lambdas)

Stella981
• 阅读 273

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
点赞
收藏
评论区
推荐文章
光头强的博客 光头强的博客
4个月前
Java面向对象试题
1、请创建一个Animal动物类,要求有方法eat()方法,方法输出一条语句“吃东西”。创建一个接口A,接口里有一个抽象方法fly()。创建一个Bird类继承Animal类并实现接口A里的方法输出一条有语句“鸟儿飞翔”,重写eat()方法输出一条语句“鸟儿吃虫”。在Test类中向上转型创建b对象,调用eat方法。然后向下转型调用eat()方
刚刚好 刚刚好
4个月前
css问题
1、在IOS中图片不显示(给图片加了圆角或者img没有父级)<div<imgsrc""/</divdiv{width:20px;height:20px;borderradius:20px;overflow:h
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
晴空闲云 晴空闲云
4个月前
css中box-sizing解放盒子实际宽高计算
我们知道传统的盒子模型,如果增加内边距padding和边框border,那么会撑大整个盒子,造成盒子的宽度不好计算,在实务中特别不方便。boxsizing可以设置盒模型的方式,可以很好的设置固定宽高的盒模型。盒子宽高计算假如我们设置如下盒子:宽度和高度均为200px,那么这会这个盒子实际的宽高就都是200px。但是当我们设置这个盒子的边框和内间距的时候,那
艾木酱 艾木酱
3个月前
快速入门|使用MemFire Cloud构建React Native应用程序
MemFireCloud是一款提供云数据库,用户可以创建云数据库,并对数据库进行管理,还可以对数据库进行备份操作。它还提供后端即服务,用户可以在1分钟内新建一个应用,使用自动生成的API和SDK,访问云数据库、对象存储、用户认证与授权等功能,可专
Stella981 Stella981
1年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
1年前
Lua 函数
【1】函数定义Lua函数定义格式如下:1optional_function_scopefunctionfunction_name(argument1,argument2,argument3...,argumentn)2function_body3returnresult_params_comma_
Wesley13 Wesley13
1年前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序selectfromtable_nameorderiddesc;2.按照指定(多个)字段排序selectfromtable_nameorderiddesc,statusdesc;3.按照指定字段和规则排序selec
Wesley13 Wesley13
1年前
PHP中的NOW()函数
是否有一个PHP函数以与MySQL函数NOW()相同的格式返回日期和时间?我知道如何使用date()做到这一点,但是我问是否有一个仅用于此的函数。例如,返回:2009120100:00:001楼使用此功能:functiongetDatetimeNow(){
helloworld_34035044 helloworld_34035044
7个月前
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
helloworld_28799839 helloworld_28799839
4个月前
常用知识整理
Javascript判断对象是否为空jsObject.keys(myObject).length0经常使用的三元运算我们经常遇到处理表格列状态字段如status的时候可以用到vue