目录
引入lambda
值捕获
使用捕获列表
参数绑定
标准库bind函数
绑定check_size的sz参数
编程例子
以下是对阅读<
在实际的编程过程中,对于某些函数,我们希望对于传入的参数列表,其中某些参数是固定的值,而另外一个参数随着调用次数的增长而传入一个像STL容器一样的可迭代对象,对象的值随着*iterator值得不同而改变,每次调用该函数后会执行iterator++,并再次通过相同的传入参数调用该函数。
我们可以向一个算法传递任意类别的可迭代对象。对于一个对象或者一个表达式,如果可以对其使用调用运算符,则称它为可调用的。一个lambda表达一个可调用单元,可以将lambda理解为一个内联函数,他直接将返回值内嵌在其它函数当中。与任何函数类似,一个lambda具有一个返回类型、一个参数列表、一个函数体,它的基本形式为:
[capture list](param list)->return type{function body}
lambda捕获可分为值捕获及引用捕获,值捕获参数是传入参数的拷贝,因此在函数执行是如果修改了外部传入参数的值,并不影响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;//局部变量
//将v1拷贝到名为f的可调用对象
auto f2=[&v1] {return v1;};
v1=0;
auto j=f2();//j为0,f2()保存了v1的引用而非拷贝
}
捕获引用有事能帮助我们进行一些常规的ostream操作来帮助我们格式化输出字符数据。
void biggies(vector &words,vector::size_type,ostream &os=cout,char c=' ')
{
//os隐式捕获,引用捕获方式;c隐式捕获,值捕获方式
for_each(words.begin(),words.end(),[&,c](const string &s){os<
lambda可以出现在一个函数中,使用其局部变量,但它只能使用那些明确指明的变量,捕获列表指引lambda在其内部包含访问局部变量所需的信息。在lambda函数中出现的变量必须由调用它的函数提供,但必须要在参数列表声明,如:
[sz](const string &a)
{
return a.size()>sz
}//正确
[](const string &a)
{
return a.size()>sz
}//错误,sz未捕获
如果lambda的捕获列表为空通常可以用函数来代替它。但是对于捕获局部变量的lambda就不是这么容易了。例如,我们用在find_if调用中的lambda比较一个string和一个给定大小。我们可以很容易地编写一个完成同样功能的函数,find_if定义在标准库头文件
bool check_size(const string &s,string::size_type sz)
{
return s.size() >=sz;
}
但是,我们不能用这个函数作为find_if的一个参数。因为find_if接受一个一元谓词,因此传递给find_if的可调用对象必须接受单一参数。
我们可以解决像check_size传递一个长度参数的问题,方法是一个新的名为bind的标准库参数,它定义在头文件functional中,可将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个可调用对象来"适应"原对象的参数列表,调用bind的一般形式为:
auto newCallable=bind(callable,arg_list)
我们可以使用bind生成一个调用check_size的对象,如下,它用一个定制作为其大小参数来调用check_size
//check6是一个可调用对象,接受一个string类型的参数,并用此string和值6来调用check_size
auto check_size=bind(check_size,_1,6);
此bind调用只有一个占位符来表示check只接受单一参数,占位符出现在arg_list的第一个未知,表示check6的此参数对应于前面所述的参数绑定下的check_size函数中的第一个参数,而第二个参数则传入值6。
需要注意的是名字_n定义在命名空间placeholders中,需要使用using namespace std::placeholders来预先声明。
string s="hello"
bool b1=check6(s)//check6(s)会调用check_size(s,6)
通过查看b1是否为true来判断字符串"hello"的长度是否>6。另外使用bind,我们可以将原来基于lambda的find_if调用
auto wc=find_if(word.begin(),words.end,[sz](Const(string &a)));
替换为如下版本:
auto wc=find_if(words.begin(),words.end(),bind(check_size,-1,sz));
利用标准库提供的适配器,我们可以实现一些不常用但功能简单的函数:
统计大于1024的值有多少个
找到第一个不等于pooh的字符串
将所有值都乘以2
定义的函数为:
std::count_if(ivec.cbegin(), ivec.cend(), std::bind(std::greater(), _1, 1024));
std::find_if(svec.cbegin(), svec.cend(), std::bind(std::not_equal_to(), _1, "pooh"));
std::transform(ivec.begin(), ivec.end(), ivec.begin(), std::bind(std::multiplies(), _1, 2));
greater、not_equal_to、mutiplies都是定义在
废话不多说,通过编程例子体会一下lambda函数和bind函数有什么不同吧。
#include
#include
#include
#include
#include
using namespace std;
using namespace::placeholders;
int main()
{
bool checkSize(const string &s,string::size_type sz);//外部函数声明
auto check6 =bind(checkSize,_1,6);
string s="hello";
vector words;
int sz=6;
words.push_back("fox");
words.push_back("jump");
words.push_back("over");
words.push_back("quick");
words.push_back("red");
words.push_back("red");
words.push_back("slow");
words.push_back("the");
words.push_back("faiofjsfs");
words.push_back("turtle");
bool b1=check6(s);
cout<sz;});
cout<<"find the element of words of which size > 6 based on bind,the result is"<<*wc< 6 based on lambda,the result is "<<*wc2<=sz;
}