lambda

来源:互联网 发布:知乎推送话题更改 编辑:程序博客网 时间:2024/04/29 13:14

lambda表达式:适用于只需要在少数地方使用

[函数的局部变量](参数列表)->返回类型{} 
  • 类似于无名的inline函数
  • 必须包含函数的局部变量和函数体(即使为空)
    例如
auto f=[]{ return 42; }cout<<f()<<endl;
  • 如果在未指定未返回类型的情况下,函数包含return语句之外的内容则返回类型为void
  • 必须使用尾置返回来设置返回类型。
[](int i)->int{if(i<0)return -i;else return i;} 
  • 不能有默认参数
  • 尽量减少捕获指针/引用
  • 适当使用 lambda 表达式。别用默认 lambda 捕获,所有捕获都要显式写出来。
    匿名函数始终要简短,如果函数体超过了五行,那么还不如起名(acgtyrant 注:即把 lambda 表达式赋值给对象),或改用函数。 如果可读性更好,就显式写出 lambd 的尾置返回类型,就像auto.

示例:
将isShorter函数改为lambda表达式

[]{const string &s1,const string &s2}  { return s1.size()<s2.size(); } 

并令其被stable_sort函数调用

stable_sort( words.begin(),words.end(),             []{const string &s1,const string &s2}               { return s1.size()<s2.size(); }  );

显式捕获:

  • []只用于局部的非static变量,lambda表达式可以直接使用局部static变量和函数之外声明的名字。
  • []值捕获的变量是在lambda表达式创建时拷贝(函数参数是在调用时拷贝)
auto f=[v1]{ return v1; };
//lambda默认不会改变被捕获的值。只能通过mutable改变auto f=[v1]()mutable{ return ++v1; };

通过lamada产生的类需要利用值捕获的变量创建构造函数,来初始化数据成员。
例如

[sz](const string &a){ return a.size()>=sz; }

相当于产生

  • 和重载了函数调用运算符的类相比,多了构造函数和私有成员。
  • 该类不包含默认构造/析构函数和赋值运算符
  • 根据捕获的数据类型决定是否包含默认的拷贝/移动构造函数
class SizeComp{    SizeComp(size_t n):sz(n){}    bool operator()(const string &s)const    { return a.size()>=sz; } private:    szie_t sz;};//调用时find_if(words.begin(),words.end(),SizeComp(sz) );
  • []引用的对象需要保证在lambda执行时存在。
auto f=[&v1]{ return v1; };//根据引用是否为const决定能否修改捕获的对象
  • 隐式捕获
[=]{参数列表}->返回类型{}[&]{参数列表}->返回类型{} 

当混合使用显式捕获和隐式捕获时

  1. 第1个元素必须是隐式捕获
  2. 显式捕获和隐式捕获的方式必须不同

对于不需要捕获局部变量的lambda可以直接由函数替代。

对于有局部变量的可以使用bind函数

auto 新可调用对象=bind(可调用对象,逗号分隔的参数列表);

当调用新可调用对象时,新可调用对象会调用并将参数传递给bind函数中的可调用对象。

参数列表可能包含占位符(_n):

  • 表示传递给新可调用对象参数的第n个参数。
  • 由于_n都位于命名空间placeholders中,而且对于每个占位符都要提供单独的声明。
using std::placeholders::_1;//为了方便:using namespace std::placeholders;

示例:

bool check_size(const string &s,string::size_type sz);auto check6=bind(check_size,_1,6);//_1对应check_size的第1个参数//6对应sz

调用时

string s="hello";bool b1=check6(s);//相当于调用check_size(s,6)

注意在bind函数中非占位符的参数将会被拷贝到返回的可调用对象中,由于bind函数无法直接使用引用,对于无法进行拷贝的对象使用ref函数/cref函数返回引用。

ref(os)

可以使用bind函数重排参数的顺序

sort( words.begin() , words.end() , bind(isShorter,_2,_1) );