C++中的lambda表达式

一、lambda表达式的声明

lambda表达式的声明格式如下:

[capture list] (params list) mutable exception-> return type { function body }

各项具体含义如下:

  1. capture list:捕获外部变量列表
  2. params list:形参列表
  3. mutable指示符:用来说用是否可以修改捕获的变量
  4. exception:异常设定
  5. return type:返回类型
  6. function body:函数体
序号格式
1[capture list] (params list) -> return type { function body }
2[capture list] (params list){ function body }
3[capture list] { function body }
  1. 默认情况下,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 );

参考

  1. msvc文档
  2. 标准库中的函数对象
  3. lambda表达式介绍
  4. hackingcpp
  5. hackingcpp-function_objects
  6. c++中的range
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值