C++的lambda表达式

本文介绍了C++中lambda表达式的使用方法,包括其语法结构、变量捕获规则及参数列表等内容。通过示例展示了如何利用lambda表达式简化代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很多高级语言里引入了lambda表达式的概念,即匿名函数。以往C++需要传入一个函数的时候,必须事先进行声明,视情况可以声明为一个普通函数然后传入函数指针,或者声明一个funtor,然后传入一个对象。

但这种传统方法太过复杂,一个简单的遍历输出就需要声明一个类或者函数,本来用于简化语法的东西却使语法大大复杂化。

比如一个用随机数填充数组的例子:

#include <iostream>
#include <cstdlib>
#include <iterator>
#include <algorithm>
using namespace std;

class mi_rand
{
    public:
        mi_rand (int start_pos, int end_pos)
        : a(start_pos), b(end_pos) 
        {}

        unsigned operator () () 
        {
            return rand() % (b-a+1) + a;
        }

    private:
        int a, b;
};

int main()
{
    const int SIZE = 20;
    int array[SIZE];
    generate_n (array, SIZE, mi_rand (1, 30));
    
    copy (array, array + SIZE, 
          ostream_iterator<int> (cout, " "));
    cout << endl;
    
    return 0;
}

示例中,generate_n的目的是使填充数组的操作简单化,但为了这种简单化却要额外声明一个类。输出数组时利用STL的确能进行语法上的简化,但是这种简化却要求对STL非常了解,而且拓展性非常差。

所幸,在c++0x标准中终于引入了lambda表达式,目前 VS 2010 和 g++ 4.5 已经进行了试验性的实现。针对上面的填充和输出操作,下面是使用lambda表达式的简化版:

#include <iostream>
#include <cstdlib>
#include <algorithm>
using namespace std;

int main()
{
    const int SIZE = 20;
    int array[SIZE];
    generate_n (array, SIZE,
                [] () { return rand() % 30 + 1; });

    for_each (array, array + SIZE, 
              [] (int a){ cout << a << " "; });
    
    return 0;
}

编译时需要注意的是,VS要求版本在2010以上,编译时需要加上 /EHsc 参数。使用g++编译的话版本要在版本4.5以上,并加上 --std=c++0x 参数。

g++目前(10年八月)的最新版本为4.51,你可以到 http://gcc.gnu.org/自行下载编译。ubuntu下可以通过 PPA for Ubuntu Toolchain Hackers直接安装二进制版本。


下面将阐述lambda表达式的语法,内容主要参考自 Lambda Expression Syntax

如图,lambda表达式由下面几个部分构成:


  1. lambda-introducer (捕获字段)
  2. lambda-parameter-declaration-list (变量列表)
  3. mutable-specification (捕获的变量可否修改)
  4. exception-specification (异常设定)
  5. lambda-return-type-clause (返回类型)
  6. compound-statement (函数体)

外部变量的捕获规则

默认情况下,即捕获字段为 [] 时,lambda表达式是不能访问任何外部变量的,即表达式的函数体内无法访问当前作用域下的变量。

如果要设定表达式能够访问外部变量,可以在 [] 内写入 & 或者 = 加上变量名,其中 & 表示按引用访问,= 表示按值访问,变量之间用逗号分隔,比如 [=factor, &total] 表示按值访问变量 factor,而按引用访问 total。

不加变量名时表示设置默认捕获字段,外部变量将按照默认字段获取,后面在书写变量名时不加符号表示按默认字段设置,比如下面三条字段都是同一含义:

[&total, factor]
[&, factor]
[=, &total]

参数列表

lambda表达式的参数列表基本和函数的一致,不过有如下限制:

  1. 参数列表不能有默认参数
  2. 不能是可变参数列表
  3. 所有的参数必须有个变量名

如果你不提供 mutable-specification, exception-specification, 以及 lambda-return-type-clause,参数列表是也可以省略的。如下面的表达式:

int main()
{
   int x = 4;
   int y = 5;
   int z = [=] { return x + y; }();
}

能否修改捕获的变量

如果在参数列表后加上了 mutable,则表示表达式可以修改按值捕获的外部变量的拷贝。

异常设置

和函数一样,可以用 throw 来限定表达式能够抛出哪些异常。

返回类型

如果设置返回类型,你需要在类型名前面加上 ->。如果你只有一个返回语句的话,返回类型可以省略,编译器将会为你做出判断。

函数体

lambda表达式的函数体和普通函数大致相同。


下面是lambda表达式的几个完整例子:

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

// The number of elements in the vector.
const int elementCount = 9;

int main() 
{
   // Create a vector object with each element set to 1.
   vector<int> v(elementCount, 1);

   // These variables hold the previous two elements of the vector.
   int x = 1;
   int y = 1;

   // Assign each element in the vector to the sum of the 
   // previous two elements.
   generate_n(v.begin() + 2, elementCount - 2, [=]() mutable throw() -> int {
      
      // Generate current value.
      int n = x + y;

      // Update previous two values.
      x = y;
      y = n;

      return n;
   });

   // Print the contents of the vector.
   for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
   cout << endl;

   // Print the local variables x and y.
   // The values of x and y hold their initial values because 
   // they are captured by value.
   cout << x << " " << y << endl;
}
#include <functional>

int main()
{
   // Assign the lambda expression that adds two numbers to an auto variable.
   auto f1 = [] (int x, int y) { return x + y; }; 

   // Assign the same lambda expression to a function object.
   using namespace std::tr1;
   function<int (int, int)> f2 = [] (int x, int y) { return x + y; };
}

更多例子请参阅 Examples of Lambda Expressions,本文的数个例子也多来源于此。

### C++ Lambda 表达式简介 C++11 引入了 lambda 表达式这一特性,使得开发者可以在需要函数的地方直接定义匿名函数对象,而无需单独声明函数。这种机制不仅简化了代码结构,还增强了程序的灵活性[^4]。 #### 基本语法 Lambda 表达式的通用形式如下: ```cpp [capture](parameters) -> return_type { body } ``` - **`capture`**: 定义如何捕获外部作用域中的变量(按值、按引用或其他方式)。 - **`parameters`**: 函数参数列表,类似于普通函数。 - **`return_type`**: 可选部分,默认情况下编译器会推导返回类型。 - **`body`**: 函数体,包含具体的逻辑实现。 --- ### 示例解析 以下是几个典型的 lambda 表达式使用场景及其对应的代码示例。 #### 1. 打印容器中的元素 通过 `std::for_each` 配合 lambda 表达式来遍历并打印向量中的数据。 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> vec = {1, 2, 3, 4, 5}; // 使用 Lambda 表达式打印每个元素 for_each(vec.begin(), vec.end(), [](int x) { cout << x << " "; }); cout << endl; return 0; } ``` 此代码展示了如何利用 lambda 表达式作为回调函数传递给标准库算法 `std::for_each`[^1]。 --- #### 2. 捕获局部变量 Lambda 表达式可以通过 `[ ]` 来捕获上下文中的变量。支持的方式有多种:按值 (`=`),按引用 (`&`) 或显式指定单个变量。 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int factor = 2; vector<int> vec = {1, 2, 3, 4, 5}; // 按值捕获变量 'factor' transform(vec.begin(), vec.end(), vec.begin(), [factor](int x) { return x * factor; }); for (auto num : vec) { cout << num << " "; } cout << endl; return 0; } ``` 在此示例中,lambda 表达式捕获了名为 `factor` 的局部变量,并将其用于计算新数组的值[^2]。 --- #### 3. 返回复杂类型的 lambda 表达式lambda 表达式的返回值较为复杂时,可以显式指定其返回类型。 ```cpp #include <functional> #include <iostream> using namespace std; int main() { auto adder = [] (int a, int b) -> int { return a + b; }; cout << adder(3, 4) << endl; // 输出 7 return 0; } ``` 上述代码显示了一个简单的加法操作,其中指定了返回类型为整数型。 --- ### 总结 Lambda 表达式极大地提高了 C++ 编程的便利性和可读性,尤其是在处理 STL 算法或者 GUI 应用开发时尤为有用。它们能够减少不必要的辅助函数定义,使代码更加紧凑高效。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值