一、lambda表达式的声明
lambda表达式的声明格式如下:
[capture list] (params list) mutable exception-> return type { function body }
各项具体含义如下:
- capture list:捕获外部变量列表
- params list:形参列表
- mutable指示符:用来说用是否可以修改捕获的变量
- exception:异常设定
- return type:返回类型
- function body:函数体
序号 | 格式 |
---|---|
1 | [capture list] (params list) -> return type { function body } |
2 | [capture list] (params list){ function body } |
3 | [capture list] { function body } |
- 默认情况下,lambda表达式的值为
const
不能修改捕获列表中的值;
二、捕获
lambda可以使用其可见范围内的外部变量,但必须要在[]
中进行声明。
int main (int argc, char *argv[])
{
int a = 123;
auto f = [a](){printf("%d\n", a);};
f();
}
2.1 值捕获
被捕获的值在lambda表达式创建的时候通过值拷贝的方式传入,因此随后对该变量的修改不会影响lambda的值。
int main (int argc, char *argv[])
{
int a = 123456;
auto f = [a](){printf("%d\n", a);};
f();
}
2.2 引用捕获
int main (int argc, char *argv[])
{
int a = 123456;
auto f = [&a](){
printf("%d\n", a); // 654321
};
a = 654321;
f();
return 0;
}
2.3 隐式捕获
隐式值捕获:
int main (int argc, char *argv[])
{
int a = 123456;
auto f = [=](){printf("%d\n", a);}; // 123456
f();
}
隐式引用捕获:
int main (int argc, char *argv[])
{
int a = 123456;
auto f = [&](){printf("%d\n", a);}; // 123456
a = 654321;
f(); // 654321
}
2.4 混和方式
上面的例子,要么是值捕获,要么是引用捕获,Lambda表达式还支持混合的方式捕获外部变量,这种方式主要是以上几种捕获方式的组合使用。
捕获方式 | 说明 |
---|---|
[] | 不捕获任何外部变量 |
[变量名, …] | 以值的形式捕获多个变量 |
[this] | 以值的形式捕获this指针 |
[=] | 以值的形式捕获所有外部变量 |
[=,&x] | 变量x以引用形式捕获,其余变量以传值形式捕获 |
[&,x] | 变量x以值的形式捕获,其余变量以引用的形式捕获 |
2.5 mutable
在Lambda表达式中,如果以传值方式捕获外部变量,则函数体中不能修改该外部变量,否则会引发编译错误。那么有没有办法可以修改值捕获的外部变量呢?这是就需要使用mutable关键字,该关键字用以说明表达式体内的代码可以修改值捕获的变量,示例:
int main (int argc, char *argv[])
{
int a = 123456;
auto f = [a]() mutable{
printf("%d\n", ++a); // 123457
};
f();
printf("%d\n", a); // 123456
return 0;
}
三、函数对象
3.1 创建函数对象
struct Functor {
bool operator()(int a, int b) { return a < b; }
};
int main(int argc, char *argv[]) {
auto f = Functor();
cout << f(1, 2) << endl;
}
3.2 函数对象和容器
C++ 标准库包含 头文件中的多个函数对象。 这些函数对象的一个用途是用作容器的排序条件。 例如, set 容器声明如下:
template<typename _Key, typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<_Key> >
class set
这里_Compare
是可以重写的:
struct Person {
int age;
Person(int age_) { age = age_; }
};
ostream &operator<<(ostream &_cout, Person p) {
_cout << "Person{" << p.age << "}";
return _cout;
}
int main(int argc, char *argv[]) {
auto f = [](Person p1, Person p2) { return p1.age < p2.age; };
// decltype(f) 这里传递表达式的类型
set<Person, decltype(f)> persons(f);
persons.emplace(50);
persons.emplace(30);
persons.emplace(10);
for (auto p : persons) {
cout << p << endl;
}
}
四、与常见算法的结合
// 第三个参数为对象
template< class InputIt, class UnaryPredicate >
InputIt find_if( InputIt first, InputIt last, UnaryPredicate p );
template< class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p );