lambda 介绍

lambda 表达形式

1
[capture list](parameter list) -> return type { function body }
  • cpature list 是一个 lambda 所在函数定义中的局部变量的列表
  • return type,parameter list 和 function body 与普通函数一样

与普通函数不同的是,lmbda必须使用尾置返回

lambda 可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体

1
2
auto f = [] {return 42;};
cout << f() << endl;

传递参数

以 vector 排序为例

1
2
vector<int> v{2,1,3};  
sort(v.begin(), v.end(), [](const int& a, const int& b){return a < b;});

lambda 不能有默认参数

捕获列表

lambda 如果想使用函数内的局部变量,需要去捕获

捕获列表 解释
[] 空捕获
[names] 函数内的局部变量名称
[&] 隐式捕获,对所有函数内实体采用引用捕获方式
[=] 隐式捕获,对所有函数内实体采用值捕获方式
[&, identifier_list] identifier_list 中的变量采用值捕获,其他引用捕获
[=, identifier_list] identifier_list 中的变量采用引用捕获,其他值捕获

返回类型

lambda 是单一的 return 语句,根据条件表达式结果可以自己推断类型

1
2
transofrm(v.begin(), v.end(), v.begin(), 
[](int i) { return i < 0 ? -i : i; });

但将条件表达式改为等价的 if-else,则必须使用尾置返回类型

1
2
3
4
5
6
7
// 编译错误
transofrm(v.begin(), v.end(), v.begin(),
[](int i) { if (i < 0) return -i else return i; });
// 添加尾置返回类型,编译成功
transofrm(v.begin(), v.end(), v.begin(),
[](int i) -> int
{ if (i < 0) return -i else return i; });

参数绑定

如果多个地方需要使用相同的操作,通常使用函数比使用 lambda 方便

假设现在有个函数

1
2
3
bool check_size(const string& s, string::size_type sz) {
return s.size() >= sz;
}

现有函数 find_if 需要调用该函数,但是 find_if 只接受一个一元谓词,那么就需要解决如何向函数传递 sz 形参的问题

1
2
#include <functional>
auto newCallable = bind(callable, arg_list);

通过 bind 可以解决该问题

1
2
3
auto check = bind(check_size, _1, 6);
auto wc = find_if(words.begin(), words,end(),
bind(check_size, _1, sz));

其中,_1 这种形如 _n 的参数为占位符,都定义在一个名为 placeholders 的命名空间中,该命名空间定义在 std 命名空间中,_1 对应声明为

1
using std::placeholders::_1;

继续介绍 bind 绑定给可调用对象中的参数关系

1
auto g = bind(f, a, b, _2, c, _1);

g(_1, _2) 映射为 f(a, b, _2, c, _1)

使用 ref()cref() 可以将传递给 bind 的对象设置为引用传递

1
2
for_each(words.begin(), words,end(),
bind(print, ref(os), _1, ' '));