C++ 11包装库,lambda的用法
lambda
lambda表达式本质是一个匿名函数对象,但是他可以定义在函数内部,一般来说,我们可以直接使用auto的对象来接收lambda对象。lambda的基本表达式格式如下:
[capture-list](parameters)-> return type{function body};
其中,capture-list是捕捉列表,用于获取函数内的局部变量来给lambda函数使用。编译器是根据"[]"的存在来判断这个是否为lambda函数。所以,即使我们什么也不需要捕捉,将其为空也不可以省略。lamda的捕捉有两种方法,传值捕捉和引用捕捉。传值捕捉的参数不能在lambda函数体内修改,但是传引用捕捉的可以。传值捕捉本质上是一种const修饰的拷贝,如果想要修改,需要在函数体后面加上mutable。
int main()
{int x = 2;int y = 9;auto ret1 = [x,&y](int a, int b){a += x;x++;//报错y++;b += y;return a + b; };auto re2 = [x,&y](int a, int b)mutable{a += x;x++;//不报错y++;b += y;return a + b; };cout << ret1(4, 5)<< endl;return 0;
除了传值捕捉,我们还可以使用隐式捕捉,在捕捉列表中写一个"="表示把需要的外部变量传值捕捉,写一个"&"表示把需要的外部变量传引用捕捉。当然,也可以进行特例捕捉。如下图所示。在局部函数域内,lambda只能捕捉前文定义的变量;如果lambda在全局位置,则捕捉列表为空,此时静态局部变量和全局变量lambda表达式是可以直接使用的。
auto ret1 = [=]{};//按需传值捕捉
auto ret2 = [&]{};//按需传引用捕捉
auto ret3 = [=,&y]{};//除了y引用捕捉以外,其他的按需传值捕捉
auto ret4 = [=,x]{};//除了x传值捕捉以外,其他的按需引用捕捉
lambda的应用主要是应用于代替仿函数,对于一些一些简短快速使用的函数体时,我们就可以使用lambda,例如在不同项的比较少时,简短的lambda表达式就比仿函数更加易懂。
lambda的原理底层就是仿函数,当我们写了一个lambda后,编译器会生成一个对应仿函数的类,我们在调用lambda的时候,其实调用的是这个类的operate()。
包装器
function
std::function的作用是可以将函数指针,仿函数lambda等可调用对象全部包装起来,方便声明可调用对象的类型。在包装成员函数的时候,有几点需要注意。
1:成员函数需要指定类域加上使用&符号才能获得地址
2:普通的成员函数有一个隐含的this指针,进行包装的时候需要传对象或者传指针过去
3:静态成员函数不需要传这个对象或者指针
4:推荐传对象,那么只要传一个匿名对象即可
#include<functional>using placeholders::_1;
using placeholders::_2;
using placeholders::_3;
int f(int a, int b)
{return a + b;
}struct Functor
{
public:int operator() (int a, int b){return (a + b) * 2;}
};class Plus
{
public:Plus(int n = 10):_n(n){ }static int plus_i(int a, int b){return (a + b) * 3;}double plus_d(double a, double b){return (a + b) * _n;}private:int _n;};
int main()
{function<int(int, int)> f1 = f;//函数function<int(int, int)> f2 = Functor();//仿函数function<int(int, int)> f3= [](int a, int b) {return a + b;};//lambda对象function<int(int, int)> f4 = &Plus::plus_i;//静态成员函数function<double(Plus*, double, double)> f5 = &Plus::plus_d;//普通成员函数 传指针function<double(Plus, double , double)> f6 = &Plus::plus_d;//普通成员函数 传对象function<double(Plus&&, double, double)> f7 = &Plus::plus_d;//普通成员函数 传右值引用}
bind
bind则是另一个包装器,bind可以用来调整参数个数和参数顺序。参数顺序相对没用,主要是参数个数。bind实际上是返回一个仿函数对象。_1代表第一个实参,_2代表第二个实参。参数个数的调整很有用,可以减少代码的书写,并且保证接口更加的简洁。如上面std::function中,如果我们传入的是一个普通成员函数,则每次都还要传一个函数对象或者这个对象的指针过去,很麻烦,当我们用bind直接绑定以后,就简洁了许多。
#include<functional>using placeholders::_1;
using placeholders::_2;
using placeholders::_3;int Sub(int a, int b)
{return a + b*5;
}int main()
{////////////////第一个功能///////////////////auto s1 = bind(Sub, _1, _2);cout << s1(1, 2) << endl;//11auto s2 = bind(Sub,_2, _1);cout << s2(1, 2) << endl;//7///////////////第二个功能///////////////////
function<double(double, double)> f8 = bind(&Plus::plus_d,Plus(),_1,_2);
}