banner
Matrix

Matrix

Abyss
email
github

Petty C++ - lambda

lambda 表达式在 C++11 之后的版本中是一种定义匿名函数的简洁语法。在一些长环境下,例如 STL 算法和异步操作,使用 lambda 作为回调函数非常自然和方便,并且 lambda 和 C++ 的函数式编程特性非常契合。

基本语法#

一个完整的 lambda 表达式语法如下:

[caputreList](paramList) mutable throw() -> returnType {
  // do something..
}

捕获列表#

lambda 以一个中括号的捕获列表开始,捕获列表用来定义哪些外部变量可以被 lambda 表达式使用,以及如何使用(传值,引用)。

捕获列表可以为空,表示 lambda 不使用闭包之外的变量,但中括号不可省略。

无论是传值还是引用方式,都可以使用默认的捕获方式,在默认捕获方式下,编译器会自动分析 lambda 需要捕获哪些外部变量。默认传值捕获方式和默认的引用捕获方式可以混用,具体用法如下:

[=] // 默认传值捕获
[&] // 默认引用捕获
[&, factor] // 除factor传值捕获外,其他变量使用引用捕获。
[=. factor] // 除factor引用捕获外,其他变量使用传值捕获。

捕获列表不允许重复声明,这种重复包括捕获方式重复和变量重复:

[&, &factor] // 错误, & 已经声明了默认的捕获方式. &factor 重复
[=, factor] // 同上
[factor, factor] // 错误,变量重复

自动捕获提供了更方便的捕获机制,但是可能会导致无意间捕获不需要的变量,可能会到之前在的内存使用增加或引入性能问题。

传值还是引用捕获的选择一般需要通过特定的场景来选择,一般来说,传值还是引用的捕获方式选择和正常函数传参方式的规则差不多。

捕获列表同样可以使用可变参数模板:

[arg...]

在类成员函数体中使用 lambda 表达式时,需要把this指针显式捕获,以提供对类成员函数和数据的访问权限。

[this, filter]

C++14 中引入了一种新的默认捕获方式,可以在捕获字句中引入并初始化新的变量,而无需把这些变量放在闭包内,这对于一些需要考虑作用域和声明周期的变量非常有用:

auto p = make_uniqure<T>(factor);

auto _lambda = [ptr = move(p)]{}

参数列表#

lambda 的参数列表行为等大多数方面类似于标准函数的参数列表。

捕获列表和参数列表在某种意义上都可以用来给闭包提供变量,但捕获列表适用于哪些在定义 lambda 时就已知且在后续调用中不会改变的变量。

捕获列表适用于在整个 lambda 的声明周期中保持不变的变量,参数列表适用于在每次调用 lambda 时都不同的变量。

std::vector<int> num = {1,2,3,4};
int fixedValue = 10;

std::for_each(num.begin(). num.end(), [fixedValue](int &x){x += fixedValue;});

在参数列表中,如果参数类型是泛型的,则使用 auto 告知编译器创建模板:

[](auto factor)

mutable#

一般地,lambda 的函数调用时 const-by-value 的,但是加入 mutable 规范后,闭包可以修改值捕获的变量:

异常#

throw()用来指示 lambda 抛出异常,可以省略,也可以使用 noexcept 指示不抛出异常:

[]() noexcpet {}
[]() throw() {}
[]() {}

返回类型#

在 lambda 中 返回类型指示可以省略,由编译器自动推断,但也有例外:

// C++11以及以前,某些编译器
[](int i){
  if (i < 0){
    return i;
  }
  else{
    return -i;
  }
} // 错误,推断类型为void

这是由于闭包的operator()推断规则:

如果主体只包含 return 一个表达式,返回类型为表达式类型,否则返回类型为 void。 (C++ 14 之前)。

lambda 体#

基本行为和一般函数一致。

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。