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/42125932/

相关文章:

c++ - Qt5 C++ 链接新窗口与 Qt Designer

c++ - 如何转发声明内部类?

c++ - 使用 android NDK 获取硬件浮点

c++ - 将初始值设定项作为参数传递

c++ - 可以从纹理生成法线贴图吗?

haskell - "iterate"是否改变了应用函数的含义?

c# - 使用匿名方法填充对象初始值设定项中的属性

c# - 从 where 子句或 IQueryable/IEnumerable 获取 lambda 表达式

c++ - 为什么单纯的C++矩阵乘法比BLAS慢100倍?

c++使用赋值运算符模拟类型转换