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;  
}
相关推荐
无 证明34 分钟前
new 分配空间;引用
数据结构·c++
别NULL5 小时前
机试题——疯长的草
数据结构·c++·算法
CYBEREXP20086 小时前
MacOS M3源代码编译Qt6.8.1
c++·qt·macos
yuanbenshidiaos6 小时前
c++------------------函数
开发语言·c++
yuanbenshidiaos6 小时前
C++----------函数的调用机制
java·c++·算法
tianmu_sama7 小时前
[Effective C++]条款38-39 复合和private继承
开发语言·c++
羚羊角uou7 小时前
【C++】优先级队列以及仿函数
开发语言·c++
姚先生977 小时前
LeetCode 54. 螺旋矩阵 (C++实现)
c++·leetcode·矩阵
FeboReigns7 小时前
C++简明教程(文章要求学过一点C语言)(1)
c语言·开发语言·c++
FeboReigns7 小时前
C++简明教程(文章要求学过一点C语言)(2)
c语言·开发语言·c++