c++ - C++11 中的 lambda 表达式是什么?

标签 c++ lambda c++11 c++-faq

C++11 中的 lambda 表达式是什么?我什么时候用一个?他们解决了在引入之前无法解决的哪一类问题?

一些示例和用例会很有用。

最佳答案

问题

C++ 包含有用的通用函数,如 std::for_eachstd::transform,它们非常方便。不幸的是,它们使用起来也很麻烦,特别是如果 functor您想要应用的是特定功能所独有的。

#include <algorithm>
#include <vector>

namespace {
  struct f {
    void operator()(int) {
      // do something
    }
  };
}

void func(std::vector<int>& v) {
  f f;
  std::for_each(v.begin(), v.end(), f);
}

如果您只在那个特定的地方使用 f 一次,那么编写整个类只是为了做一些微不足道的一次性事情似乎有点过分了。

在 C++03 中,您可能会想编写如下内容,以将仿函数保持在本地:

void func2(std::vector<int>& v) {
  struct {
    void operator()(int) {
       // do something
    }
  } f;
  std::for_each(v.begin(), v.end(), f);
}

但是这是不允许的,f 不能传递给 template C++03 中的函数。

新的解决方案

C++11 引入了 lambda,允许您编写内联的匿名仿函数来替换 struct f。对于小的简单示例,这可以更清晰地阅读(它将所有内容都放在一个地方)并且可能更易于维护,例如以最简单的形式:

void func3(std::vector<int>& v) {
  std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}

Lambda 函数只是匿名仿函数的语法糖。

返回类型

在简单的情况下,lambda 的返回类型会为您推导出来,例如:

void func4(std::vector<double>& v) {
  std::transform(v.begin(), v.end(), v.begin(),
                 [](double d) { return d < 0.00001 ? 0 : d; }
                 );
}

然而,当您开始编写更复杂的 lambda 时,您很快就会遇到编译器无法推导出返回类型的情况,例如:

void func4(std::vector<double>& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });
}

要解决此问题,您可以使用 -> T 显式指定 lambda 函数的返回类型:

void func4(std::vector<double>& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) -> double {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });
}

“捕获”变量

到目前为止,除了在其中传递给 lambda 的内容外,我们还没有使用任何其他变量,但我们也可以在 lambda 中使用其他变量。如果你想访问其他变量,你可以使用捕获子句(表达式的 []),到目前为止,这些示例中还没有使用它,例如:

void func5(std::vector<double>& v, const double& epsilon) {
    std::transform(v.begin(), v.end(), v.begin(),
        [epsilon](double d) -> double {
            if (d < epsilon) {
                return 0;
            } else {
                return d;
            }
        });
}

您可以通过引用和值来捕获,您可以分别使用 &= 指定它们:

  • [&epsilon, zeta] 通过引用捕获 epsilon,通过值捕获 zeta
  • [&] 通过引用捕获 lambda 中使用的所有变量
  • [=] 按值捕获 lambda 中使用的所有变量
  • [&, epsilon] 通过引用捕获 lambda 中使用的所有变量,但通过值捕获 epsilon
  • [=, &epsilon] 按值捕获 lambda 中使用的所有变量,但按引用捕获 epsilon

生成的 operator() 默认为 const,这意味着当您默认访问它们时,捕获将是 const。这具有相同输入的每次调用都会产生相同结果的效果,但是您可以 mark the lambda as mutable请求生成的 operator() 不是 const

关于c++ - C++11 中的 lambda 表达式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58567553/

相关文章:

c++ - 在 C++ 中从 C 库正确初始化 typedef 结构

c++ - 函数可以命名为default吗?

c++ - 有人请解释一下它的行为是什么?

C++ - 使用另一个类的构造函数实例化一个对象

c++ - "Capture"lambda 函数中的变量解析为参数

java - Spark 序列化的奇怪之处

c++ - C++11 是否支持 C11 的新特性?

c++ - 如何创建包含 n 次相同类型的类型列表(用于可变参数模板)?

c++ - 简单的欧拉物理,奇怪的行为

c++ - 将 lambda 隐式转换为函数 ptr 以创建类