【C++】Lambda 表达式

C++ Lambda

用C++创建一个Lambda表达式

带有参数的C++ Lambda函数

带有返回类型的C++ Lambda函数

C++的Lambda函数捕获子句

按值捕获

通过引用捕获

例子: C++ Lambda函数作为STL算法的参数


C++ Lambda

C++ Lambda 表达式允许我们定义匿名函数对象(functors 仿函数),这些对象既可以内联使用,也可以作为单个参数传递。

Lambda表达式是在C++11版本中被引入,以采用更方便、更简洁的方式创建匿名仿函数。

通过使用Lambda表达式,我们不再需要在一个单独的类或结构中重载()操作符。


用C++创建一个Lambda表达式

基本的Lambda表达式可以是这样:

auto hello = []() {
  // lambda 函数体
};

其中,

  • [] 被称为 lambda引用器 表示lambda表达式的开始
  • () 被称为 参数列表 与平常函数中的()操作符相似

上列代码等价于:

void hello() {
  // 函数体
}

同一般函数一样,我们可以用下列方法调用lambda表达式:

hello();

注意: 使用了auto关键字来自动判断lambda表达式的返回类型


例1: C++ Lambda 函数

#include <iostream>
using namespace std;

int main() {

  // 用Lambda函数打印 Hello world
  auto hello = []() {
    cout << "Hello World!";
  };

  // 调用lambda函数
  hello();

  return 0;
}

输出

Hello World!

在上面的例子中,我们创建了一个简单的程序,用C++ lambda表达式打印了“Hello World!”

I. 创建了lambda函数并将其分配给一个名为 hello 的变量

auto hello = []() {
  cout << "Hello World!";
};

II. 用了hello作为变量名称,同时加上()操作符完成了对lambda函数的调用:

// 打印 "Hello World!"
hello(); 

带有参数的C++ Lambda函数

同正则函数一样,lambda表达式也可以接受参数。比如:

#include <iostream>
using namespace std;

int main() {

  // 带有两个整数型的lambda函数
  //  带参并打印他们的和
  auto add = [] (int a, int b) {
   cout << "Sum = " << a + b;
  };

  // 调用lambda表达式
  add(100, 10);

  return 0;
}

输出

Sum = 110

在上面的例子中,我们创建了一个lambda函数,能够接收两个整数参数并显示它们的总和。

auto add = [] (int a, int b) {
  cout << "Sum = " << a + b;
};

等价于:

void add(int a, int b) {
  cout << "Sum = " << a + b; 
}

然后我们通过传递两个整数参数来调用lambda函数:

// 返回 110
add(100, 10);

带有返回类型的C++ Lambda函数

与普通函数一样,C++ lambda表达式也可以有一个返回类型。

编译器可以根据返回语句隐式地推断出lambda表达式的返回类型。

auto add = [] (int a, int b) {
  // 返回 int 类型数据
  return a + b;
};

在上述例子中,我们没有明确定义lambda函数的返回类型。这是因为return语句是有一个,编译器能够判断清楚。

但是对于不同数据类型的多个返回语句,我们必须明确地定义其类型。比如说:

auto operation = []  (int a, int b,  string op) -> double {
  if (op == "sum") {
    // 返回int类型
    return a + b;
  } 
  else {
    // 返回double类型
    return (a + b) / 2.0;
  }
};

注意上面的代码 -> double。明确地定义了返回类型为double,因为有多个语句根据op的值返回不同的类型数值。

不管各种返回语句返回的是什么类型的值,它们都将被显式转换为double类型返回。


例 2: C++ Lambda - 显式返回类型

#include<iostream>
using namespace std;

int main() {

  // lambda 函数显示返回类型 'double'
  // 根据操作符返回sum还是average
  auto operation = []  (int a, int b,  string op) -> double {
    if (op == "sum") {
      return a + b;
    }
    else {
      return (a + b) / 2.0;
    }
  };

  int num1 = 1;
  int num2 = 2;

  // 使用sum来标记完成对num1,num2的计算
  auto sum = operation(num1, num2, "sum"); 
  cout << "Sum = " << sum << endl;

  // 使用average来标记完成对num1,num2的计算
  auto avg = operation(num1, num2, "avg"); 
  cout << "Average = " << avg;

  return 0;
}

输出

Sum = 3
Average = 1.5

在上面的例子中,我们创建了一个lambda函数来寻找操作数:

  • 两个整数和 sum
  • 两个整数的平均 avg
auto operation = []  (int a, int b,  string op) -> double {
  if (op == "sum") {
    // 返回 'int'
    return a + b;
  } 
  else {
    // 返回 'double'
    return (a + b) / 2.0;   
  }
};

在main()中,我们需要首先通过传递 "sum "作为第三个参数,从而得出num1和num2的总和:

auto sum = operation(num1, num2, "sum");

在这里,尽管lambda返回一个整数值,但它被显式转换为double类型。

然后,我们通过传递一些其他的字符串作为参数来得出两数的平均值:

auto avg = operation(num1, num2, "avg");

C++的Lambda函数捕获子句

默认情况下,lambda函数不能访问嵌套函数中的变量。如果需要访问这些变量,我们则要使用捕获子句。

可以通过以下两种方式捕获变量:

按值捕获

这类似于按值调用。在这里,lambda函数创建时会对实际值做一次拷贝。

注意: 我们只能读取lambda函数体中的变量,但不能修改它。

通过将值捕获过来的lambda表达式:

int num_main = 100;

// 从函数体中获取对num_main的访问
auto my_lambda = [num_main] () {
  cout << num_main;
};

这里,[num_main]允许lambda访问num_main变量。

如果我们把num_main从捕获子句中删除,我们将会犯一个错误,因为num_main不能从lambda函数体中访问。

通过引用捕获

这类似通过引用的方式来捕获,即lambda函数可以访问变量地址。

注意: 我们可以读取变量,也可以在lambda函数中修改它。

一个带有引用捕获的基本lambda表达式如下:

int num_main = 100;

// 访问num_main变量的地址
auto my_lambda = [&num_main] () {
  num_main = 900;
};

在[&num_main]中我们使用了&操作符。这表明我们正在捕捉num_main变量的地址。


例3:C++ Lambda按值捕获

#include<iostream>
using namespace std;

int main() {

  int initial_sum = 100;

  // 按initial_sum的值进行捕获
  auto add_to_sum = [initial_sum] (int num) {
    return initial_sum + num;
  };

  int final_sum = add_to_sum(78);
  cout << "100 + 78 = " << final_sum;

  return 0;
}

输出

100 + 78 = 178

在上面的例子中,我们创建了一个lambda表达式,返回一个名为initial_sum的局部变量和一个整数参数num的总和。

auto add_to_sum = [initial_sum] (int num) {
  return initial_sum + num;
};

这里,[initial_sum]通过捕获initial_sum的值传入到函数内。

然后,我们调用该函数并将其返回值存储在final_sum变量中。

int final_sum = add_to_sum(78);

在这里lambda函数中:

  • num 是 78
  • initial_sum 是 100

因此结果变为 100 + 78 也就是 178.

注意:假设我们想通过数值来捕获多个变量。比如:

auto my_lambda = [a, b, c, d, e] (){
  // lambda 函数
}

正如所见,如果将变量一个一个列出将使整个过程变得十分繁琐,为了使操作更加简单,我们可以简单地尝试用隐式按值捕获,例如:

auto my_lambda = [=] (){
  // lambda 函数
}

这里,[=]表示函数中的所有变量都被值所捕获。


例4:C++ Lambda通过引用捕获

#include <iostream>
using namespace std;

int main() {

  int num = 0;

  cout << "Initially, num = " << num << endl;
  
  // [&num] 捕获 num 变量的地址
  auto increment_by_one = [&num] () {
    cout << "Incrementing num by 1.\n";
    num++;
  };

  // invoke lambda function
  increment_by_one();

  cout << "Now, num = " << num << endl;

  return 0;
}

输出

Initially, num = 0
Incrementing num by 1.
Now, num = 1

在上面的例子中,我们创建了一个lambda函数,将一个局部变量num的值增加了1。

auto increment_by_one = [&num] () {
  cout << "Incrementing num by 1.\n";
  num++;
};

这里[&num]被用来通过引用来捕获num。

一开始,num的值是0。

然后,我们调用lambda表达式increment_by_one()。使num的值增加了1。

注意: 为了捕获嵌套函数中的所有变量, 我们可以通过使用隐式的引用捕获例如:

auto my_lambda = [&] (){
  // lambda 函数
}

这里,[&]表示所有的变量都通过引用来捕获。


例子: C++ Lambda函数作为STL算法的参数

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {

  // 初始化整数类型vector
  vector<int> nums = {1, 2, 3, 4, 5, 8, 10, 12};

  int even_count = count_if(nums.begin(), nums.end(), [](int num) {
    return num % 2 == 0;
  });

  cout << "There are " << even_count << " even numbers.";

  return 0;
}

输出

There are 5 even numbers.

在上面的例子中,我们在count_if算法中使用了一个lambda函数来计算nums向量中的全部偶数:

int even_count = count_if(nums.begin(), nums.end(), [](int num) {
  return num % 2 == 0;
});

请注意,我们用lambda表达式作为count_if的第三个参数。这个lambda表达式接收整数num。如果num是偶数,则返回true。

另外,我们还把lambda表达式写在了参数列表中。

[](int num) {
  return num % 2 == 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

干吃咖啡豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值