C++总结(9):Lambda表达式详解

C++ Lambda表达式允许我们定义匿名函数对象,它既可以内联使用,也可以作为参数传递。它以更方便简洁的方式创建匿名函数,因为我们不需要在单独的类或结构中重载()运算符。

文章目录

  • [1 基本Lambda语法](#1 基本Lambda语法)
  • [2 Lambda函数捕获语法](#2 Lambda函数捕获语法)
    • [2.1 值捕获](#2.1 值捕获)
    • [2.2 引用捕获](#2.2 引用捕获)
  • [3 STL中将Lambda函数用作参数](#3 STL中将Lambda函数用作参数)

1 基本Lambda语法

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

复制代码
auto greet = []() {
  // lambda function body
};

其中:

  • []:表示lambda表达式的开始
  • ():参数列表,类似于普通函数的()运算符

这里auto关键字来自动推断lambda表达式的返回类型。上面的代码等价于:

复制代码
void greet() {
  // function body
}

所以就像普通函数一样,我们可以直接调用greet()

例:基本Lambda函数

复制代码
#include <iostream>
using namespace std;

int main() {

  // create a lambda function that prints "Hello World!"
  auto greet = []() {
    cout << "Hello World!";
  };

  // call lambda function
  greet();

  return 0;
}

创建了lambda函数并将其分配给一个名为greet的变量,然后使用greet变量和()运算符调用lambda函数。

例:带参数的Lambda函数

复制代码
#include <iostream>
using namespace std;

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

  // call the lambda function
  add(100, 78);

  return 0;
}

上面的Lambda函数等于:

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

例:带返回值的Lambda函数

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

复制代码
auto add = [] (int a, int b) {
  // always returns an 'int'
  return a + b;
};

在上面的例子中,我们没有明确地定义Lambda函数的返回类型。这是因为只有一个return语句,它总是返回一个整数值。

但是如果有多个return语句,必须显式地定义类型

复制代码
auto operation = []  (int a, int b,  string op) -> double {
  if (op == "sum") {
    // returns integer value
    return a + b;
  } 
  else {
    // returns double value
    return (a + b) / 2.0;
  }
};

上面的代码 ->double明确地将返回类型定义为 double。因此,无论各种return语句返回什么类型的值,它们都会被显式转换为double类型。

2 Lambda函数捕获语法

默认情况下,Lambda函数不能访问封闭函数(包含Lambda表达式的函数)的变量。为了访问这些变量,我们使用捕获子句。

2.1 值捕获

这类似于按值调用函数,在这种情况下,Lambda表达式创建时会拷贝实际值,所以原变量的值是无法修改的。

复制代码
int num_main = 100;
// get access to num_main from the enclosing function
auto my_lambda = [num_main] () {
  cout << num_main;
};

在这里, num_main允许Lambda访问num_main变量。完整例子:

复制代码
#include<iostream>
using namespace std;

int main() {

  int initial_sum = 100;

  // capture initial_sum by value
  auto add_to_sum = [initial_sum] (int num) {
    // here inital_sum = 100 from local scope
    return initial_sum + num;
  };

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

  return 0;
}

假设我们想按值捕获多个变量:

复制代码
auto my_lambda = [a, b, c, d, e] (){
  // lambda body
}

这样就显得很冗长,我们可以隐式按值捕获所有变量

复制代码
auto my_lambda = [=] (){
  // lambda body
}

这里的[=]表示封闭函数内的所有值都被捕获。

2.2 引用捕获

这类似于按引用调用函数,在这种情况下,Lambda表达式可以访问变量的地址。

复制代码
int num_main = 100;

// access the address of num_main variable
auto my_lambda = [&num_main] () {
  num_main = 900;
};

完整例子:

复制代码
#include <iostream>
using namespace std;

int main() {

  int num = 0;

  cout << "Initially, num = " << num << endl;
  
  // [&num] captures num by reference
  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;
}

和按值捕获类似,如果要按引用捕获封闭函数中的所有变量 ,可以用[&]

复制代码
auto my_lambda = [&] (){
  // lambda body
}

3 STL中将Lambda函数用作参数

来看一个求vector元素中的偶数个数的例子:

复制代码
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {

  // initialize vector of integers
  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;
}

这里的count_if<algorithm>中的一个函数,用于对指定范围内的元素执行某种条件测试,并返回满足该条件的元素数量。函数原型如下:

复制代码
template< class InputIt, class UnaryPredicate >  
int count_if( InputIt first, InputIt last, UnaryPredicate p );

其中:

  • firstlast:起始和结束迭代器
  • p:一元谓词,用于测试每个元素是否满足某个条件

函数会遍历从firstlast的元素,并对每个元素调用谓词p。如果谓词对于某个元素返回true,则count_if函数会增加计数器。最后,函数返回满足谓词的元素数量。


现在再回来看:

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

这里Lambda表达式作为count_if的第三个参数,接受整数num,如果num是偶数,则返回true。

  • 这里不需要写返回值,auto也不用写,编译器会自动推断。

上面的例子就等价于:

复制代码
#include <iostream>  
#include <vector>  
#include <algorithm>  
  
using namespace std;  

bool isEven(int num) {  
  return num % 2 == 0;  
}  
  
int main() {  
  vector<int> nums = {1, 2, 3, 4, 5, 8, 10, 12};  
  int even_count = count_if(nums.begin(), nums.end(), isEven);  
  cout << "There are " << even_count << " even numbers.";  
  return 0;  
}
相关推荐
xiaolang_8616_wjl4 小时前
c++文字游戏_闯关打怪2.0(开源)
开发语言·c++·开源
夜月yeyue4 小时前
设计模式分析
linux·c++·stm32·单片机·嵌入式硬件
无小道5 小时前
c++-引用(包括完美转发,移动构造,万能引用)
c语言·开发语言·汇编·c++
FirstFrost --sy6 小时前
数据结构之二叉树
c语言·数据结构·c++·算法·链表·深度优先·广度优先
Tanecious.7 小时前
C++--map和set的使用
开发语言·c++
Yingye Zhu(HPXXZYY)7 小时前
Codeforces 2021 C Those Who Are With Us
数据结构·c++·算法
liulilittle8 小时前
LinkedList 链表数据结构实现 (OPENPPP2)
开发语言·数据结构·c++·链表
无聊的小坏坏8 小时前
三种方法详解最长回文子串问题
c++·算法·回文串
山河木马8 小时前
前端学习C++之:.h(.hpp)与.cpp文件
前端·javascript·c++
2401_891957318 小时前
list的一些特性(C++)
开发语言·c++