风骚的lambda

在c++11中,增加了不少的特性,才发现先的c++是如此的风骚

lambda

一个lambda表达式表示一个可调用的代码单元。我们可以将其理解为一个未命名的内联函数。与任何函数类似,一个lambda具有一个返回类型、一个参数列表、和一个函数体,但与函数不同,lambda可能定义在函数内部。一个lambda表达式具有如下形式

[capture list](parameter list)-> return type{function body}
  • capture list(捕获列表)是一个lambda**所在函数定义局部变量**的列表(通常为空)
  • return type:返回类型
  • parameter list:参数列表
  • function body:函数体

后面三个和普通函数一样,但是lambda必须使用尾置返回来指定类型,尾置返回简单说明在文章后面
* 我们可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体
* 在lambda中忽略括号和参数列表等价于指定一个空参数列表。
* 如果忽略返回类型,lambda根据函数体中的代码推断出返回类型,如只有一个return语句,则从返回表达式类型推断出来
* 如果lambda的函数体包含任何单一return语句之外的内容,且未指定返回类型,则返回void

忽略参数列表和返回类型的example

auto f = [] {return 42;};
cout << f()  << endl;//打印42
// 注意是f()而不是f

向lambda传递参数

[](const string &a,const string &b)
   {return a.size()<b.size();}

//使用
//按长度排序,长度相同的单词维持字典序
stable_sort(words.begin(),words.end(),
            [](const string &a,const string &b)
              {return a.size()<b,size();} );

空捕获列表表面此lambda不使用它所在函数中的任何局部变量。

使用捕获列表

一个lambda通过将局部遍历包含在其捕获列表中来指出将会使用这些变量,在这个例子中,lambda会捕获sz,并只有单一的string参数

[sz]{const string &a}
    {return a.size()>=sz};
  • 捕获列表只用于局部非static变量,lambda可以直接使用局部static变量和他所在函数之外声明的名字

完整的biggies

void biggies(vector<sting &words>,vector<string>::sizetype sz)
{
    elimDups(words); //将word按字典序排毒,删除重复单词
    //按长度排序,长度相同单词维持字典序
    stable_sort(words.begin(),words.end(),
                [](const string &a,const string &b)
                  {return a.size()<b,size();} );
    //获取一个迭代器指向第一个满足size()>sz的元素
    auto wc = find_if(words.begin(),words.end(),
                      [sz](const string &a)
                           { return a,size()>=size; });
    //计算满足size>=sz的元素的数目
    auto count = words.end()-wc;
    cout<<count<<" "<<make_pliral(count,"word",'s')<<" of length "<<sz<<" or longer"<<endl;
    //打印长度大于等于给定值的单词,每个单词后面接一个空格
    for_each(wc,words.end(),
            [](const string &s){cout<<s<<" ";});
    cout<<endl;
}

lambda捕获和返回

每个lambda表达式的类型是独一无二的。当向一个函数传递一个lambda时,同时定义了一个新类型和该类型的一个对象。
默认情况下,从lambda生成的类都包含一个对应 该lambda所捕获的变量的数据成员。
可以使用decltype关键字声明一个该类型成员

值捕获

被捕获的值是在lambda创建时拷贝,而不是调用时拷贝:

void fcn1()
{
    size_t v1=42;  //局部变量
    //将v1拷贝到名为f的可调用对象
    auto f = [v1]{return v1};
    v1=0;
    auto j = f();  //j为42,f保存了我们创建它时v1的拷贝
}

引用捕获

void fcn2()
{
    size_t v1=42;  //局部变量
    //对象f2包含v1引用
    auto f2 = [&v1]{return v1};
    v1=0;
    auto j = f2();  //j为0,f保存了v1的引用
}

如果必须采用引用方式捕获一个变量,必须保证被引用的对象在lambda执行的时候是存在的

隐式捕获

除了显示列出我们希望使用的来自所在函数的变量之外,还可以指示编译器根据lambda体中的代码来推断我们需要使用那些变量。
为了指示编译器推断捕获列表,应在捕获列表中写一个&或=。&告诉编译器采用捕获引用方式,=表示采用值捕获方式。
例如重写的find_if

//sz为隐式捕获,值捕获方式
wc = find_if(words.begin(),words.end,
            [=](const string &s){return s.size()>=sz; });

如果希望对一部分变量采用值捕获,对其他变量采用引用捕获,可以混合使用隐式捕获和显示捕获,但捕获列表中的第一个元素必须是一个&或=

可变lambda

如果我们希望能改变一个被捕获的变量的值,就必须在参数列表首加上关键字mutable

void fcn3()
{
  size_t v1 = 42;
  //f可以改变它所捕获的变量的值
  auto f=[v1]() mutable { return ++v1; };
  v1=0;
  auto j=f(); // j为43
}

尾置返回

一般来讲,尾置返回类型是为了使用decltype,或者纯粹让代码变得更可读。
decltype的例子如下,譬如说你可能不知道a+b到底返回什么类型:

template<typename T, typename U>
auto Add(T t, U u) -> decltype(t + u)
{
    return t + u;
}

这样你不仅可以Add(1, 2),还可以Add(3.0, 4.0f),甚至还可以Add(“VczhIsAGenius”, 7)了。

上述例子来自: https://segmentfault.com/q/1010000003763661

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值