风骚的lambda

来源:互联网 发布:ps cs6 mac破解版 编辑:程序博客网 时间:2024/05/16 12:52

  • lambda
    • 向lambda传递参数
    • 使用捕获列表
    • lambda捕获和返回
      • 值捕获
      • 引用捕获
      • 隐式捕获
    • 可变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 0