什么是 lambda 表达式

一个 lambda 表达式提供一个简明的方式来创建简单的功能的对象。lambda 表达式是一个 prvalue,其结果对象称为闭包对象 ,其行为类似于函数对象。

“lambda 表达”这个名字起源于 lambda 演算 ,这是一种数学形式主义,由 Alonzo Church 于 20 世纪 30 年代发明,旨在研究逻辑和可计算性问题。Lambda 演算是 LISP的基础, LISP是一种函数式编程语言。与 lambda 演算和 LISP 相比,C++ lambda 表达式共享未命名的属性,并从周围的上下文中捕获变量,但它们缺乏操作和返回函数的能力。

lambda 表达式通常用作带有可调用对象的函数的参数。这可能比创建一个命名函数更简单,该函数仅在作为参数传递时使用。在这种情况下,lambda 表达式通常是首选,因为它们允许内联定义函数对象。

lambda 通常由三部分组成:捕获列表 [],可选参数列表 () 和 body {},所有这些都可以为空:

[](){}                // An empty lambda, which does and returns nothing

捕获列表

[]捕获列表。默认情况下,lambda 无法访问封闭范围的变量。捕获变量使其可以在 lambda 中访问,可以是副本,可以是引用 。捕获的变量成为 lambda 的一部分; 与函数参数相比,它们在调用 lambda 时不必传递。

int a = 0;                       // Define an integer variable
auto f = []()   { return a*9; }; // Error: 'a' cannot be accessed
auto f = [a]()  { return a*9; }; // OK, 'a' is "captured" by value
auto f = [&a]() { return a++; }; // OK, 'a' is "captured" by reference
                                 //      Note: It is the responsibility of the programmer
                                 //      to ensure that a is not destroyed before the
                                 //      lambda is called.
auto b = f();                    // Call the lambda function. a is taken from the capture list and not passed here.

参数列表

()参数列表,与常规函数几乎相同。如果 lambda 不带参数,则可以省略这些括号(除非你需要声明 lambda mutable)。这两个 lambdas 是等价的:

auto call_foo  = [x](){ x.foo(); };
auto call_foo2 = [x]{ x.foo(); };

Version >= C++ 14

参数列表可以使用占位符类型 auto 而不是实际类型。通过这样做,此参数的行为类似于函数模板的模板参数。当你想要在通用代码中对向量进行排序时,以下 lambdas 是等效的:

auto sort_cpp11 = [](std::vector<T>::const_reference lhs, std::vector<T>::const_reference rhs) { return lhs < rhs; }; 
auto sort_cpp14 = [](const auto &lhs, const auto &rhs) { return lhs < rhs; }; 

功能体

{}正文,与常规函数相同。

叫一个 lambda

lambda 表达式的结果对象是一个闭包 ,可以使用 operator() 调用(与其他函数对象一样):

int multiplier = 5;
auto timesFive = [multiplier](int a) { return a * multiplier; }; 
std::out << timesFive(2); // Prints 10

multiplier = 15;
std::out << timesFive(2); // Still prints 2*5 == 10

退货类型

默认情况下,推导出 lambda 表达式的返回类型。

[](){ return true; };

在这种情况下,返回类型是 bool

你还可以使用以下语法手动指定返回类型:

[]() -> bool { return true; };

可变的 Lambda

默认情况下,lambda 中的值捕获的对象是不可变的。这是因为生成的闭包对象的 operator() 默认为 const

auto func = [c = 0](){++c; std::cout << c;};  // fails to compile because ++c
                                              // tries to mutate the state of
                                              // the lambda.

使用关键字 mutable 可以允许修改,这使得更近的对象的 operator()const

auto func = [c = 0]() mutable {++c; std::cout << c;};

如果与返回类型一起使用,mutable 就会出现在它之前。

auto func = [c = 0]() mutable -> int {++c; std::cout << c; return c;};

一个例子来说明 lambda 的有用性

在 C++ 11 之前:

Version < C++ 11

// Generic functor used for comparison
struct islessthan
{
    islessthan(int threshold) : _threshold(threshold) {}

    bool operator()(int value) const
    {
        return value < _threshold;
    }
private:
    int _threshold;
};

// Declare a vector
const int arr[] = { 1, 2, 3, 4, 5 };
std::vector<int> vec(arr, arr+5);

// Find a number that's less than a given input (assume this would have been function input)
int threshold = 10;
std::vector<int>::iterator it = std::find_if(vec.begin(), vec.end(), islessthan(threshold));

从 C++ 11 开始:

Version >= C++ 11

// Declare a vector
std::vector<int> vec{ 1, 2, 3, 4, 5 };

// Find a number that's less than a given input (assume this would have been function input)
int threshold = 10;
auto it = std::find_if(vec.begin(), vec.end(), [threshold](int value) { return value < threshold; });