Lambda


Lambda 表达式,实际上就是提供了一个类似匿名函数的特性

Lambda 表达式的基本语法如下:

[capture_list] (params_list) mutable exception -> return type { function body }

capture__list:捕获外部变量列表,方式包括=,&,this等,不可省略。
params_list:形参列表,无参数可省略。
mutable:指示符,用来说明是否可以修改捕获的变量,因为Lambda默认是const属性。
exception:异常设定,可以用于指定函数抛出的异常。
return type:返回类型。
function:函数体。

捕获类型如下:

  • []:默认不捕获任何变量;
  • [=]:将Lambda表达式所在范围内的所有可见局部变量按值传递,即在函数体内都可使用。;
  • [&]:将Lambda表达式所在范围内的所有可见局部变量按引用传递,即在函数体内都可使用。;
  • [x]:以值传递捕获x,其它变量不捕获,无法对x进行修改,因为默认下x是const类型,需要mutable指示符的介入;
  • [x...]:以包展开方式值传递捕获参数包变量;
  • [&x]:仅以引用捕获x,其它变量不捕获;
  • [&x...]:以包展开方式引用捕获参数包变量;
  • [=, &x]:默认以值传递捕获所有变量,但是x是例外,通过引用捕获;
  • [&, x]:默认以引用捕获所有变量,但是x是例外,通过值传递捕获;
  • [this]:通过引用捕获当前对象(其实是复制指针);
  • [*this]:通过值传递方式捕获当前对象;

  int main()

  {
    int x = 10;
    int y = 20;
    auto print = [](int s) {std::cout << "value is " << s << std::endl;};
    auto lambAdd = [x](int a) { 
      // x++; 此处复制捕获,x是只读,不允许自增,编译会报错
      return a + x;
    };


  auto lambAdd2 = [&x](int a, int b) {
    x = x+5;  //引用捕获,可以改变x
    return a + b + x;
  };


  auto iSum = lambAdd(10);
  auto iSum2 = lambAdd2(10, 11);
  print(iSum);
  print(iSum2);

  return 0;
}

 

  mutable

  从代码可以看出,复制捕获不允许修改变量值,而引用捕获则允许修改变量值。那么如果我想使用复制捕获,又想修改变量的值呢,这时我们就想起来有个关键字,叫做mutable,它允许在常成员函数中修改成员变量的值

mutable可以取消Lambda的常量属性,因为Lambda默认是const属性;multable仅是让Lamdba函数体修改值传递的变量,但修改后并不影响外部的变量。

所以我们可以给lambda表达式指定mutable关键字,如下:

int main()
{
  int x = 10;
  int y = 20;
  auto print = [](int s) {std::cout << "value is " << s << std::endl;};
  auto lambAdd = [x](int a) mutable {
    x++;//允许x被修改
    return a + x;
  };
  auto iSum = lambAdd(10);
  print(iSum);
  print(x);

  return 0;
}

执行结果如下:

    value is 21
    value is 10

所以加上mutable以后就可以对复制捕获进行修改,但有一点,它的修改出了lambda表达式以后就无效了

 

  1. 值捕获与参数传值类似,值捕获的前提是变量可以拷贝,不同之处则在于,被捕获的变量在Lambda表达式被创建时拷贝,而非调用时才拷贝:

void lambda_value_capture() {
  int value = 1;
  auto copy_value = [value] { //表达式被创建
    return value;
  };


  value = 100;
  auto stored_value = copy_value();
  std::cout << "stored_value = " << stored_value << std::endl;// 这时, stored_value == 1, 而value == 100. 因为copy_value 在创建时就保存了一份value 的拷贝
}


2. 引用捕获与引用传参类似,引用捕获保存的是引用,值会发生变化。
void lambda_reference_capture() {
  int value = 1;
  auto copy_value = [&value] {
    return value;
  };


  value = 100;
  auto stored_value = copy_value();
  std::cout << "stored_value = " << stored_value << std::endl; // 这时, stored_value == 100, value == 100. 因为copy_value 保存的是引用
}

 

lambda表达式赋值

不能用一个lambda表达式给另外一个赋值,但可以进行初始化拷贝。

int main()
{
  auto a = [] { cout << "A" << endl; };
  auto b = [] { cout << "B" << endl; };

  //a = b; // 非法,lambda无法赋值
  auto c(a); // 合法,生成一个副本
  return 0;
}

 

  exception

  exception 声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw(int)。(没有找到代码实例)