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

2022-02-10 19:09:40 浏览数 (1)

问题

C 11 的 lambda 表达式是什么?什么时候去用它?主要用它解决什么问题呢?

回答

起因

C 03 时代,头文件 <algorithm> 有很多方便使用的泛型函数,例如 std::for_eachstd::transform。但有的时候这些函数用起来又很麻烦,尤其是存在 functor 的情况下。

代码语言:javascript复制
#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 一次,但是你还是需要像上面那样定义一个 strcut,如果这种类似的情况比较多,那么代码看起来就显得很乱。

你可能会想到 functor 本地化的办法来解决这个问题,就像下面这样,

代码语言:javascript复制
void func2(std::vector<int>& v) {
  struct {
    void operator()(int) {
       // do something
    }
  } f;
  std::for_each(v.begin(), v.end(), f);
}

但是 C 03 (C 11 已经支持)是不支持这种用法的,因为 f 不能应用于 模板函数。

C 11 新的解决方案

C 11 的 lambda 提供了一种匿名函数,可以完美解决这个问题。

代码语言:javascript复制
void func3(std::vector<int>& v) {
  std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}

lambda 的返回类型

如果你的 lambda 很简单,那么编译器可以自动推断出你的返回类型,

代码语言:javascript复制
void func4(std::vector<double>& v) {
  std::transform(v.begin(), v.end(), v.begin(),
                 [](double d) { return d < 0.00001 ? 0 : d; }
                 );
}

但如果你的 lambda 比较复杂,比如下面这样,返回类型既可能是整型也可能是浮点型,

代码语言:javascript复制
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;
            }
        });
}

那么你可以手动给它指定你要返回的类型,你需要这么做,

代码语言:javascript复制
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;
            }
        });
}

捕获变量(Capturing variables)

那 lambda 如何在函数体内使用外部的变量呢?其实很简单,在 [] 中填入你想捕获的就可以了。

代码语言:javascript复制
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] 仅捕获 epsilon 变量,且是值捕获
  • [v, epsilon] 仅捕获 v 和 epsilon 变量,且是值捕获(多个变量以 , 隔开)
  • [&epsilon] 引用捕获 epsilon 变量
  • [&] 引用捕获所有变量
  • [=] 值捕获所有变量
  • [&, epsilon] 除了 epsilon 是值捕获,其它的都引用捕获
  • [=, &epsilon] 除了 epsilon 是引用捕获,其它的都值捕获
  • [this] 值捕获 this 指针

0 人点赞