lambda表达式用法
C++11 提供了对匿名函数的支持,称为 Lambda 函数(也叫 Lambda 表达式)。Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。Lambda 表达式本质上与函数声明非常类似。
首先看一些基本的lambda表达
#一
[capture](parameters)->return-type{body}
//例如
[](int x, int y) -> int { int z = x + y; return z + x; }
int main(){
int a = 1;
int b = 2;
auto lambda = []{return a + b;};
//error! 空捕获列表,无法使用作用域内其他变量
auto lambda = [](int a, int b){return a + b;};
//success
auto lambda = [=]{return a + b;};
//success, 值传递
auto lambda = [=]{a++; b++; return a + b;};
//error! 值传递无法修改变量值 因为根据合成的类该调用运算符是const成员函数,
//在const成员函数中,不能有修改数据的操作,会报错。
//不可修改a,b,如果需要修改则在(参数)后添加限定符mutable
size_t v1 = 42;
auto lambda = [=]()mutable{return ++v1};
//一般lambda值传递无法修改拷贝的变量,但加上关键词mutable便可变了,相当于去掉const不是const成员函数
auto lambda = [&]{a++; b++; return a + b;};
//success, 引用传递
auto lambda = [&a, b]{a++; b++; return a + b;};
//error, 变量a引用传递,变量b值传递,故b不可修改
auto lambda = [this]{a++; b++; return a + b;};
[this]表示值传递方式捕捉当前的this指针
}
#二
[capture](parameters)->return-type{body}
//混合隐式和显式捕获,首先第一个元素必须一个是&或者=,且第二个显示捕获的变量必须与隐式不同的方式
[&, c]{ return cout <<c;}//正确:方式不同,第一个引用捕获,第二个值捕获
[&, &c]{ return cout <<c;}//错误,方式一样
[=, &c]{ return cout <<c;}//正确:方式不同,第一个值捕获,第二个引用捕获
[=, c]{ return cout <<c;}//错误,方式一样
指定lambda返回类型:C++14 或C++17修改了限制,return中还有其他语句时可以判断返回类型了,并不需要指定返回类型。
#三:
transform(vi.begin(), vi.end(), vi.begin(), [](int i)
{if (i < 0) return -i; else return i; });
//实际上当一个函数传递一个lambda时,同时定义了一个新类型和该类型的一个对象:传递的参数
//旧是此编译器生成的类类型的未命名对象,类似的,使用auto定义一个用lambda初始化的变量时
//定义了一个从lambda生成的类型的对象
//类中含有一个重载的函数调用运算符
以下:
stable_sort(word.begin(), word.end(), [](const string&a, const string &b)
{return a.size() < b.size(); });
//行为类似于下面这个类的一个未命名对象
class ShorterString
{
public:
bool operator()(const string&s1, const string &s2)const
{return s1.size() < s2.size();}
}
//则可以用这个类替代lambda表达式替代,重写,当stable_sort的内部代码每次比较两个string
//时就会“调用”这一对象,此时该对象将调用运算符的函数体进行判断是否返回ture
stable_sort(word.begin(), word.end(), ShorterString())
#如果含有捕获参数,是值传递的参数则合成的类中有该参数的数据成员,用捕获的量来初始化来该成员
#如果是引用则不需要:类似以下
auto wc= find_if(words.begin(),words.end(),[sz](const string&a){return a.size()<=sz})
//捕获的sz以值传递的方式获得,拷贝到n再去初始化类中的sz
class ShorterString
{
public:
ShorterString(int n):sz(n){};
bool operator()(const string&s1)const
{return s1.size() < sz;}
privata:
size_t sz;
}
lambda产生的类不含默认构造函数,赋值运算符及默认析构函数,如果有值传递参数,则需要提供实参的构造函数
其他拷贝/移动构造函数则通常要根据捕获的数据成员类型而定
箭头运算符:
在这里插入代码片
function模板:
function 能表示共享同一种调用形式,尽管他们的类型是不相同的,function能包含所有的可调用对象。以下:
class PFH
{
public:
int operator()(int i, int j)
{
return i*i + j*j;
}
};
int a_dd(int i, int j)
{
return i + j;
}
int divi_des(int i, int j)
{
return i / j;
}
map <string, function<int(int, int)>> binops =
{
{"+",add},//函数指针
{"-",std::minus<int>()},//标准库函数
{"/",divi_des} ,// 自定义函数
{"*",[](int i, int j) {return i * j; }} ,//未命名的lambda
{"%" ,mod},//命名的lmabda
{"_2",PFH()}//自定义的函数对象
};
cout << binops["+"](5, 2) <<endl;
cout << binops["-"](5, 2) << endl;
cout << binops["/"](5, 2) << endl;
cout << binops["*"](5, 2) << endl;
cout << binops["%"](5, 2) << endl;
cout << binops["_2"](5, 2) << endl;
但如果有重载函数,用函数指针或lambda来消除二义性