一.lambda表达式
形式:
[capture](parameters)->return-type {body}
[]叫做捕获说明符,表示一个lambda表达式的开始。接下来是参数列表,即这个匿名的lambda函数的参数,->return-type表示返回类型,如果没有返回类型,则可以省略这部分。
变量捕获与lambda闭包实现
string name;
cin >> name;
[&](){cout << name;}();
lambda函数能够捕获lambda函数外的具有自动存储时期的变量。函数体与这些变量的集合合起来叫闭包。
[] 不截取任何变量
[&} 截取外部作用域中所有变量,并作为引用在函数体中使用
[=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
[=, &foo] 截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用
[bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
[x, &y] x按值传递,y按引用传递
[this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。
lambda的类型有两种方式可以获得:
auto my_lambda_func = [&](int x) { /*...*/ };
;
std::function< int(int) > Functional= [](int i)-> int { return i; };
**lambda表达式的作用是代替回调函数,以表达式的形式直接传给调用函数实参,函数的功能性质会更加直观,**如下:
二.function模本类的使用
由上面的sort函数衍生出一个新的问题就是,sort函数是怎么接收一个表达式作为实参的,如果是传入一个普通的函数的话,那么可以通过函数指针来定义形参,从而传进函数,也就是常见的回调函数的使用方法。
如果我们要想某个函数里传入变量、对象或表达式,那我们必须要知道他们所对应的类型才能来定义形参从而才能在函数内部使用,但是lambda表达式的类型我们并不知道,而使用auto需要最开始就初始化,这里会报错,所以function就出现了,它是一种一种通用、多态的函数封装。
std::function的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lambda表达式、
函数指针、以及其它函数对象等。
std::function对象是对C++中现有的可调用实体的一种类型安全的包裹(我们知道像函数指针这类可调用实体,是类型不安全的)。
最简单的理解就是:
通过std::function对C++中各种可调用实体(普通函数、Lambda表达式、函数指针、以及其它函数对象等)的封装,形成一个新
的可调用的std::function对象;让我们不再纠结那么多的可调用实体。一切变的简单粗暴。
用处:
std::function对象最大的用处就是在实现函数回调,使用者需要注意,它不能被用来检查相等或者不相等,但是可以与NULL或者
nullptr进行比较。
好处:
std::function实现了一套类型消除机制,可以统一处理不同的函数对象类型。
以前我们使用函数指针来完成这些;现在我们可以使用更安全的std::function来完成这些任务。
实例:
sort函数第三个形参就是下面这种形式
std::function<bool(int,int)> f
在sort函数内就可以通过f(3,4)这种来调用lambda函数体;
2.用结构体的操作函数代替lambda表达式
这里sort的第三个形参与上一个是一样的,不同的是用类来实现了回调函数。
上面两种一个是用lambda,一个是类分别实现了回调函数的功能,但是用的是function完全封装类别,更加的安全。
3.在不增加形参列表的情况下,传入表达式的同时在传入一个函数外变量
我们在用回调函数是传入一个函数,实参只能是回调函数的名字不能带参数,想要从函数外在传进一个变量的话,只能通过增加函数的形参列表传进去。
int backcall(int x)
{
return x;
}
int test(int(*f)(int),int a)
{
return f(a);
}
int main()
{
test(backcall,3);
}
如果我们想通过一个形参既能传入一个函数还能传入一个函数外变量,那么可以通过,lambda表达式和仿函数(也即类的操作符重载函数)如下所示:
如果我们想通过调用函数的形式来实现这样的目标则函数的返回类型必须是function类;
返回的表达式可以是,lambda表达式可以是函数也可以是仿函数;
如下:
这时的函数也可以这样表达
std::cout << Predicator({3, 4, 5, 6, 7})(3);
它和下面这种表达式等价的
int eval4(std::function<int(int)> f, int x = 3){return f(x);}
std::cout << eval4(Predicator({3, 4, 5, 6, 7}),3);
后面跟着两个小括号,第一个传递的是外层的,第二个传递的是内层lambda需要的参数,相当于将函数名和第一个参数合为了一个名字在调用第二个参数。
这里和上边一样可以用相同的表达式;
下面这段代码里码出了一些可以用的语法方式:
#include<functional>
#include <vector>
#include<iostream>
#include<algorithm>
std::function<int(int)> Predicator(std::vector<int>&& ys)
{
return [ys = std::move(ys)](int x) {
return find(begin(ys), end(ys), x) != end(ys);
};
}
std::function<int(int)> Predicator1(std::vector<int>&& ys)
{
return [ys = std::move(ys)](int x) {
return find(begin(ys), end(ys), x) != end(ys);
};
}
int maybe(int x)
{
std::cout << "x" << std::endl;
return x;
}
std::function<int(int)> test(int&& a)
{
// return [](int x) {
// return x;
// };
std::cout << " a"<< std::endl;
return maybe;
}
double eval(std::function<double(double)> f, double x = 2.0){return f(x);}
double eval1(int(*f)(int), int x = 2){return f(x);}
int eval2(int (*f)(int,int), int x = 2, int y = 0) { return f(x, y); }
int eval3(std::function<int(int,int)> f, int x = 2,int y=1){return f(x,y);}
int eval4(std::function<int(int)> f, int x = 3){return f(x);}
struct FIEWNFK
{
bool operator()(int a,int b)const
{
std::cout << "+";
return a < b;
}
};
struct FIEWNFK1
{
private:
std::vector<int> ys;
public:
FIEWNFK1(std::vector<int>& theYs)
:ys(std::move(theYs))
{
}
bool operator()(int x)const
{
return find(begin(ys),end(ys),x)!=end(ys);
}
};
std::function<int(int)> f = [=f](int x)
{
return x == 0 ? 0 : f(x - 1);
};
int
main()
{
std::vector<int> numbers = {7, 1, 12, 2, 8, 3, 11, 4, 9, 5, 13, 6, 10};
std::function<double(double)> f0 = [](double x){return 1;};
auto f1 = [](double x){return x;};
auto f2 = [](int a, int b) { return a < b; };
auto f4 = [](double x){return x;};
// decltype(f0) fa[3] = {f0,f1,[](double x){return x*x;}};
// std::vector<decltype(f0)> fv = {f0,f1};
// fv.push_back ([](double x){return x*x;});
// for(int i=0;i<fv.size();i++) std::cout << fv[i](2.0) << "\n";
// for(int i=0;i<3;i++) std::cout << fa[i](2.0) << "\n";
// for(auto &f : fv) std::cout << f(2.0) << "\n";
// for(auto &f : fa) std::cout << f(2.0) << "\n";
std::cout
<< eval(f0) << "\n";
std::cout << eval(f1) << "\n";
std::cout << eval([](double x){return 1;}) << "\n";
std::cout << eval1([](int x){return x;}) << "\n";
// eval2(f2, 3, 4);//看来用函数指针的形式做
std::cout<<eval3(f2, 4, 3);
std::sort(begin(numbers), end(numbers), FIEWNFK{});
std::cout<<eval3(FIEWNFK{}, 4, 3);
FIEWNFK a;
std::cout<<a(3, 4);
std::cout << eval4(Predicator({3, 4, 5, 6, 7}));
std::cout << Predicator({3, 4, 5, 6, 7})(3);
std::cout << eval4(Predicator1({3, 4, 5, 6, 7}));
std::cout << Predicator1({3, 4, 5, 6, 7})(3);
//std::cout << eval4(test(1));
std::cout <<test(1)(2);
int c = 4;
std::cout << eval([c](double x) { return c; });
return 0;
}