首页 > 编程语言 >C++ lambda函数

C++ lambda函数

时间:2025-01-17 12:29:46浏览次数:3  
标签:变量 int 捕获 C++ v1 lambda 函数

lambda函数是C++11标准新增的语法糖,也称为lambda表达式或匿名函数。

lambda函数的特点是:距离近、简洁、高效和功能强大。

 语法:

​[](const int& no) -> void { cout << "亲爱的" << no << "号:我是一个一个aaaa。\n"; };

代码示例:

#include <iostream>

#include <vector>

#include <algorithm>

using  namespace std;

// 表白函数。

void zsshow(const int & no)  {  

cout << "亲爱的" << no << "号:我是一个一个aaaa。\n";

}

// 表白仿函数。

class czs   

{

public:

void operator()(const int & no) {

cout << "亲爱的" << no << "号:我是一个一个aaaa。\n";

}

};

int main()

{

vector<int> vv = { 5,8,3 };   // 存放编号的容器。

// 第三个参数是普通函数。

for_each(vv.begin(), vv.end(), zsshow);  

// 第三个参数是仿函数。

for_each(vv.begin(), vv.end(), czs());       

// 第三个参数是lambda表达式。

for_each(vv.begin(), vv.end(),

[](const int& no) {

cout << "亲爱的" << no << "号:我是一个一个aaaa。\n";

}

);

}

一、参数列表

参数列表是可选的,类似普通函数的参数列表,如果没有参数列表,()可以省略不写。

与普通函数的不同:

  1. lambda函数不能有默认参数。
  2. 所有参数必须有参数名,因为lambda函数声明与定义必在一起,现写现用。
  3. 不支持可变参数。

二、返回类型

用后置的方法书写返回类型,类似于普通函数的返回类型,如果不写返回类型,编译器会根据函数体中的代码推断出来。

如果有返回类型,建议显式的指定,自动推断可能与预期不一致。

三、函数体

类似于普通函数的函数体。

四、捕获列表

通过捕获列表,lambda函数可以访问父作用域中的非静态局部变量(静态局部变量可以直接访问,不能访问全局变量)。

捕获列表书写在[]中,与函数参数的传递类似,捕获方式可以是值和引用。

以下列出了不同的捕获列表的方式。

1)值捕获

与传递参数类似,采用值捕获的前提是变量可以拷贝。

与传递参数不同,变量的值是在lambda函数创建时拷贝,而不是调用时拷贝。

例如:

size_t v1 = 42;

auto f = [ v1 ]  { return v1; }; // 使用了值捕获,将v1拷贝到名为f的可调用对象。

v1 = 0;

auto j = f();    // j为42,f保存了我们创建它是v1的拷贝。

由于被捕获的值是在lambda函数创建时拷贝,因此在随后对其修改不会影响到lambda内部的值。

默认情况下,如果以传值方式捕获变量,则在lambda函数中不能修改变量的值。

2)引用捕获

和函数引用参数一样,引用变量的值在lambda函数体中改变时,将影响被引用的对象。

size_t v1 = 42;

auto f = [ &v1 ]  { return v1; };  // 引用捕获,将v1拷贝到名为f的可调用对象。

v1 = 0;

auto j = f();    // j为0。

如果采用引用方式捕获变量,就必须保证被引用的对象在lambda执行的时候是存在的。

3)隐式捕获

除了显式列出我们希望使用的父作域的变量之外,还可以让编译器根据函数体中的代码来推断需要捕获哪些变量,这种方式称之为隐式捕获。

隐式捕获有两种方式,分别是[=]和[&]。[=]表示以值捕获的方式捕获外部变量,[&]表示以引用捕获的方式捕获外部变量。

   int a = 123;

    auto f = [ = ]  { cout << a << endl; }; //值捕获

    f(); // 输出:123

    auto f1 = [ & ] { cout << a++ << endl; }; //引用捕获

    f1(); //输出:123(采用了后++)

    cout << a << endl; //输出 124

4)混合方式捕获

lambda函数还支持混合方式捕获,即同时使用显式捕获和隐式捕获。

混合捕获时,捕获列表中的第一个元素必须是 = 或 &,此符号指定了默认捕获的方式是值捕获或引用捕获。

需要注意的是:显式捕获的变量必须使用和默认捕获不同的方式捕获。例如:

int i = 10;

int  j = 20;

auto f1 = [ =, &i] () { return j + i; }; // 正确,默认值捕获,显式是引用捕获

auto f2 = [ =, i] () { return i + j; }; // 编译出错,默认值捕获,显式值捕获,冲突了

auto f3 = [ &, &i] () { return i +j; }; // 编译出错,默认引用捕获,显式引用捕获,冲突了

5)修改值捕获变量的值

在lambda函数中,如果以传值方式捕获变量,则函数体中不能修改该变量,否则会引发编译错误。

在lambda函数中,如果希望修改值捕获变量的值,可以加mutable选项,但是,在lambda函数的外部,变量的值不会被修改。

    int a = 123;

    auto f = [a]()mutable { cout << ++a << endl; }; // 不会报错

    cout << a << endl; // 输出:123

    f(); // 输出:124

    cout << a << endl; // 输出:123

6)异常说明

lambda可以抛出异常,用throw(…)指示异常的类型,用noexcept指示不抛出任何异常。

五、lambda函数的本质

当我们编写了一个lambda函数之后,编译器将它翻译成一个类,该类中有一个重载了()的函数。

1)采用值捕获

采用值捕获时,lambda函数生成的类用捕获变量的值初始化自己的成员变量。

例如:

int a =10;

int b = 20;

auto addfun = [=] (const int c ) -> int { return a+c; };

int c = addfun(b);    

cout << c << endl;

等同于:

​class Myclass

{

int m_a; // 该成员变量对应通过值捕获的变量

public:

Myclass( int a ) : m_a(a){}; // 该形参对应捕获的变量

// 重载了()运算符的函数,返回类型、形参和函数体都与lambda函数一致。

int operator()(const int c) const

{

return m_a + c;
}
};

默认情况下,由lambda函数生成的类是const成员函数,所以变量的值不能修改。如果加上mutable,相当于去掉const。这样上面的限制就能讲通了。

2)采用引用捕获

如果lambda函数采用引用捕获的方式,编译器直接引用就行了。

唯一需要注意的是,lambda函数执行时,程序必须保证引用的对象有效.      

注:此课件及源代码来自B站up主:码农论坛,该文章仅作为本人学习笔记及交流学习使用。

标签:变量,int,捕获,C++,v1,lambda,函数
From: https://blog.csdn.net/qq_74224788/article/details/145204376

相关文章

  • C++文件操作-随机存取&&缓冲区及流状态
    目录文件操作-随机存取1.fstream类2.文件的位置指针3.随机存取文件操作-缓冲区及流状态1.文件缓冲区2.流状态文件操作-随机存取1.fstream类fstream类既可以读文本/二进制文件,也可以写文本/二进制文件。fstream类的缺省模式是ios::in|ios::out,如果文件不存在,以只......
  • SQL-按自定义格式进行编号的SQL自定义函数.090119
    生成格式如:DT.EMP.0000000001的自增emp_id,加入EmpBaseINfo表中。--生成格式如DT.EMP.0000000001  【Vegas Add】ALTERFUNCTION[dbo].[Get_EmpBaseInfo_AccountID](@RowIDasint)RETURNSnvarchar(50) as begin    declare@oidnvarchar(50)    dec......
  • 【C++】IO流
    ......
  • 我的第一个云函数
    我的第一个云函数我们以定义一个将两个数字相加的函数作为我们第一个云函数的示例。在项目根目录找到project.config.json文件,新增cloudfunctionRoot字段,指定本地已存在的目录作为云开发的本地根目录示例:{"cloudfunctionRoot":"cloudfunctions/"}project.config.j......
  • 云函数
    云函数云函数即在云端(服务器端)运行的函数。在物理设计上,一个云函数可由多个文件组成,占用一定量的CPU内存等计算资源;各云函数完全独立;可分别部署在不同的地区。开发者无需购买、搭建服务器,只需编写函数代码并部署到云端即可在小程序端调用,同时云函数之间也可互相调用。一个云函......
  • 【机器学习:十七、多分类问题和Softmax函数】
    1.多分类问题1.1多分类问题定义多分类问题是指一个模型需要从多个类别中选择一个类别作为输出的任务。与二分类问题不同,多分类任务中类别的数量n>2......
  • 深入探索:函数栈帧的神秘世界及其背后原理
    文章目录什么是函数栈帧理解函数栈帧的作用函数栈帧的创建和销毁解析什么是栈?相关寄存器和汇编指令函数栈帧的创建和销毁过程准备环境函数栈帧的创建函数栈帧的销毁前言:在C语言中,函数是程序的基本单位,我们通过函数来实现特定的功能。然而,函数如何被调用、返回值如......
  • 【c++】【Linux】内存碎片
    【c++】【Linux】内存碎片内碎片分配给进程未被使用的部分当内存被分配给某个进程时,分配的内存块可能比实际需求稍大,未被使用的部分称为内碎片。例如,如果需要3.6k内存此时根据buddy伙伴系统内存分配方式最少分配4k为一页那其中0.4k未被使用的内存就是内碎片如果使......
  • 生成函数
    生成函数浅讲感觉这是一个非常牛逼的东西,写了点自己的感悟,可能讲得不是很清楚。生成函数的定义就比较牛,将数列\(\{a_i\}\)写成一个函数\(A(x)=\sum{a_ix^i}\)的形式叫做普通生成函数。此处的\(x^i\)没有实际意义,只是一个占位符。对于生成函数来说,绝大数多项式的运算法则......
  • 使用QFuture和QFutureWatcher实现不阻塞界面的Async函数
    简述很多时候,在Qt里面需要运行一个耗时函数的时候,为了避免阻塞界面,需要放入非主线程去执行。实现这样处理的方法有好几种,例如:写一个继承自QThread类,实现run接口;写一个继承自QObject的类,添加槽函数执行任务,创建对象,移入一个QThread中进行调用;写一个QRunnable的子类,创建对象,添......