【C++】c++11新特性(二)--Lambda函数及function(包装器)

目录

Lambda函数

基本概念

基本语法

lambda 捕获(capture)

1. 不捕获任何变量

2. 按值捕获

3. 按引用捕获

4. 混合捕获

5. 捕获this 指针

包装器 function

基本概念

使用场景

1. 给function对象赋值

 2. 作为函数参数和返回值

  3. 存储在容器中

4. 绑定成员函数和带参数的函数


Lambda函数

基本概念

       lambda 函数(也被称为匿名函数或lambda表达式)是一种简洁的方式,用于定义在代码块中使用的临时函数对象。

       lambda 函数特别适用于需要小函数但又不希望定义完整函数或函数对象的情况。通常与 STL 算法结合使用,为算法提供自定义的操作。

基本语法

lambda 函数的基本语法如下:

[Capture-list]  (Parameters)  Mutable -> Return-Type  { function-body }

(Capture list) --- 捕获列表

        用于捕获外部作用域的变量,使得这些变量可以在lambda函数体内部被访问。捕获列表可以是以值捕获([] 或 [=]);也可以是按引用[&] 或 [&variable])。

  (Parameters) --- 参数列表

        与普通函数的参数列表类似,用于指定lambda函数的输入参数。

  (Return-Type) --- 返回类型

         可以显式指定lambda函数的返回类型。

  (function-body) --- 函数体

        包含lambda函数的实际代码逻辑;在该函数体内,除了可以使用其参数外,还可以使用所有捕获 到的变量。

注意:

1. 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来 判断接下来的代码      是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda 函数使用。因此,该部      分不能省略

2. 参数列表。如果不需要参数传递,则可以连同()一起省略

3. mutable。默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使      用该修饰符时,参数列表不可省略(即使参数为空)。

4. 返回类型。没有返回值时此部分可省略返回值类型明确情况下,也可省略,由编译器对      返回类型进行推导。

总结:参数列表返回类型在lambda表达式中是可选的捕获列表函数体必需的

lambda 捕获(capture)

1. 不捕获任何变量

当lambda表达式不需要访问任何外部变量时,可以使用空的捕获子句。

最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情


int main() 
{  // 最简单的lambda表达式, 该lambda表达式没有任何意义auto lambda = []() {  cout << "This lambda captures nothing." << endl;  };  lambda(); // 输出: This lambda captures nothing. return 0;  
}

2. 按值捕获

       捕获变量按值意味着在lambda创建时,捕获的变量会被复制一份到lambda中,lambda内部使用的是这份复制的变量,因此原始变量的后续修改不会影响lambda内部的变量。


//按值捕获 特定变量
int test_val() 
{int x = 10;int y = 15;auto lambda = [x]() {cout << "Value of x inside lambda: " << x << endl;  //输出 10};x = 20; // 修改外部的x,不会影响lambda内部的x  lambda(); // 输出: Value of x inside lambda: 10  return 0;
}//按值捕获 所有变量
int test_all() 
{int x = 10;int y = 15;auto lambda = [=]() {cout << "Value of x and y inside lambda: " << x + y << endl; //输出 25};x = 20; // 修改外部的x,不会影响lambda内部的x  lambda(); // 输出: Value of x inside lambda: 25  return 0;
}

3. 按引用捕获

       捕获变量按引用意味着lambda函数体内部直接使用原始变量的引用,因此原始变量的任何修改都会在lambda内部反映出来。

//按引用捕获 特定变量
int test_val() 
{int x = 10;int y = 15;  // y没有被捕获auto lambda = [&x]() {cout << "Value of x inside lambda: " << x << endl; };x = 20; // 修改外部的x,会影响到lambda内部的x  lambda(); // 输出: Value of x inside lambda: 20  return 0;
}//按引用捕获 所有变量
int test_all() 
{int x = 10;int y = 15;auto lambda = [&]() {cout << "Value of x and y inside lambda: " << x << " " << y << endl; };x = 20; // 修改外部的x,会影响lambda内部的x y = 30; // 修改外部的y,会影响lambda内部的y lambda(); // 输出: Value of x and y inside lambda: 20 and 30 return 0;
}

4. 混合捕获

可以同时按值按引用捕获不同的变量。

int main()
{int x = 10;int y = 15;// 按值捕获x,按引用捕获yauto lambda = [x, &y]() {cout << "Value of x and y inside lambda: " << x << " " << y << endl; };x = 20;   // 修改外部的 x,不会影响lambda内部的 x y = 30;   // 修改外部的 y,会影响lambda内部的 ylambda(); // 输出: Value of x inside lambda: 10  30  return 0;
}

5. 捕获this 指针

在类的成员函数中,可以通过捕获this指针来访问类的成员变量和成员函数

class A {
public:A() : a(0) {}void func1(){int b = 4; // 捕获bauto lambda = [b]() {cout << "捕获b:" << b;return; };lambda();  // 输出 lambda 内部的 b : 4}void func2(){int b = 4; // b没有被捕获// 传 this 指针auto lambda = [this]() {cout << "捕获a:" << a;return; };lambda();  // 输出 lambda 内部的 a : 0}private:int a;
};int main() 
{A obj;obj.func1();obj.func2();return 0;
}

如果把上面类A的成员函数 func1中 按值捕获的 b 变量 在 lambda表达式中进行修改,即func1函数变成如下形式:

void func1()
    {
        int b = 4; // 捕获b
        auto lambda = [b]() {

            b += 6;
            cout << "捕获b:" << b;
            return; 
        };

        lambda();  // 输出 lambda 内部的 b : 4
    }

此时,编译器会报错:“b”: 无法在非可变 lambda 中修改通过复制捕获

因为在默认情况下,lambda函数中有一个 operator()操作符,其默认为const,即lambda函数总是一个const函数;捕获列表中的变量a,直接成为lambda函数成员,且由其构造函数在初始化列表中直接初始化。

因此,lambda表达式不可以修改按值捕获的变量,因为operator() 被编译器默认扩展为const属性

如果像强制修改,可将关键字mutable应用lambda表达式,这样会使编译器扩展的operator()为不带const属性的接口,便可以修该被捕获的变量!

以上func1函数体中的 lambda 表达式 修改成如下形式:

auto lambda = [b] () mutable {

            b += 6;       //ok
            cout << "捕获b:" << b;
            return; 
        };

包装器 function

基本概念

function是一个通用的、类型安全的函数对象包装器,它允许将任何可调用的目标(如函数、lambda表达式、函数对象或其他function对象)赋值给它,并可以像调用普通函数一样调用它。function通常与lambda表达式一起使用,以实现更灵活和可重用的代码。

说明:使用function需要包含 <functional>头文件,然后定义function对象,并指定其调用签名。调用签名定义了该函数对象接受的参数类型和返回类型

#include <iostream>  
#include <functional> 
using namespace std; int add(int a, int b) 
{  return a + b;  
}  int main() 
{  // 定义一个function对象,接受两个int参数并返回一个int  function<int(int, int)> func;  // ... 后续可以将func与任何匹配签名的可调用对象关联起来  return 0;  
}

使用场景

1. 给function对象赋值

可以将 普通函数、lambda表达式、函数对象或其他function对象赋值给function

int add(int x, int y)
{return x + y;
}int main() 
{function<int(int, int)> func;// 赋值一个普通函数  func = add;cout << func(2, 4) << endl; // 输出6// 赋值一个lambda表达式  func = [](int x, int y) { return x * y; };cout << func(2, 5) << endl; // 输出7  // 赋值另一个function对象(如果它们的签名兼容)  function<int(int, int)> anotherFunc = add;func = anotherFunc;cout << func(2, 6) << endl; // 输出8 return 0;
}

 2. 作为函数参数和返回值

function对象可以作为函数参数传递,也可以作为函数的返回值。这使得编写更加通用和灵活的代码。

int add(int x, int y)
{return x + y;
}// 作为函数参数传递
void process(function<int(int, int)> ft, int a, int b) 
{int result = ft(a, b);cout << "Result: " << result << endl;
}// 作为函数返回值
function<int(int, int)> funcOperation()
{return [](int a, int b) { return a - b; };
}int main() 
{process(add, 2, 3);          process([](int a, int b) { return a * b; }, 2, 3); process(funcOperation(), 5, 3); return 0;
}

  3. 存储在容器中

function对象可以存储在标准库容器中,如vectormap,使得可以动态地管理一组函数对象。

int main() 
{vector<function<int(int)>> funcs;funcs.push_back([](int x) { return x * x; });funcs.push_back([](int x) { return x * x * x; });for (const auto& e : funcs) {cout << e(2) << endl;   // 输出4和8  }return 0;
}

4. 绑定成员函数和带参数的函数

如果想要绑定类的成员函数或者带参数的函数,需要使用bind或者lambda表达式来捕获所需的上下文。

class Plus
{
public:static int plusi(int a, int b){return a + b;}int plusd(int a, int b){return a + b;}};int main() 
{Plus obj;// 类的静态成员函数function<int(int, int)> func4 = &Plus::plusi;cout << func4(1, 2) << endl;//类的非静态成员函数function<double(Plus, double, double)> func5 = &Plus::plusd;cout << func5(Plus(), 1, 2) << endl;// 使用bind绑定成员函数  function<int(int, int)> memberFunc = bind(&Plus::plusd, &obj, placeholders::_1, placeholders::_2);cout << memberFunc(3, 4) << endl; // 输出: 7// 使用lambda表达式捕获对象指针并调用成员函数  function<int(int, int)> lambdaMemberFunc = [&obj](int x, int y) { return obj.plusd(x, y); };cout << lambdaMemberFunc(4, 5) << endl; // 输出: 9  return 0;
}

说明:

1. function可以绑定到任何可调用的目标,包括成员函数和带有绑定参数的函数。这需要使用 bind 或 lambda表达式 来捕获所需的上下文

2. function是空类型安全的,这意味着它会在运行时检查所赋值的可调用对象是否与它的签名兼容。如果不兼容,将会抛出std::bad_function_call异常


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/796292.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

已解决java.util.zip.DataFormatException: 数据格式异常的正确解决方法,亲测有效!!!

已解决java.util.zip.DataFormatException: 数据格式异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 报错原因 解决思路 解决方法 核实数据的完整性和来源 验证数据是否为有效的ZIP格式 检查与编码相关的问题 正确使用AP…

【数据库(MySQL)基础】以MySQL为例的视图、存储过程与触发器

文章目录 1. 视图1.1 视图创建1.2 视图查询1.3 视图修改1.4 视图删除1.5 视图检查选项1.5.1 cascaded检查选项1.5.1.1 这个选项存在为了避免什么问题&#xff1f;1.5.1.2 怎么利用这个选项1.5.1.3 子视图 1.5.2 local检查选项1.5.2.1 local示例 1.6 视图更新及作用 2. 存储过程…

如何保护大模型API安全

大模型的崛起正在改变着我们对机器学习和人工智能的理解&#xff0c;它们不仅提供了令人惊叹的预测和分析能力&#xff0c;还在各行各业的应用中发挥着重要作用。通过提供 API&#xff0c;用户无需了解底层实现细节&#xff0c;使大型模型能够更好地与用户和应用程序进行交互&a…

C++IO类,输入输出缓冲区,流状态

我们的程序已经使用了很多IO库设施&#xff1a; istream(输入流)类型&#xff0c;提供输入操作。ostream(输出流)类型&#xff0c;提供输出操作。cin&#xff0c;一个istream对象&#xff0c;从标准输入读取数据。写入到标准错误。cout&#xff0c;一个ostream对象&#xff0c…

Windows 下融合使用开源组件进行视频内容分析,shotcut ,autocut 剪辑 whisper智能化编辑双语字幕等

文章大纲 whisperautocut油管 视频分析视频数据下载下载字幕数据开源视频剪辑工具shotcut参考文献学习路径下面以这个黄仁勋访谈视频为例简要介绍分析的步骤 https://youtu.be/lXLBTBBil2Uwhisper https://github.com/openai/whisper提升: 安装如果需要在conda 中使用 ffmpeg …

电商技术揭秘七:搜索引擎中的SEO关键词策略与内容优化技术

文章目录 引言一、关键词策略1.1 关键词研究与选择1. 确定目标受众2. 使用关键词研究工具3. 分析搜索量和竞争程度4. 考虑长尾关键词5. 关键词的商业意图6. 创建关键词列表7. 持续监控和调整 1.2 关键词布局与密度1. 关键词自然分布2. 标题标签的使用3. 首次段落的重要性4. 关键…

C 语言中的 end, _end 符号

使用 man 3 end 可以看到相关符号的解释 这些符号不是在 C 语言文件和头文件中定义的&#xff0c;它们是 ld 在链接所有 .o 文件的时候自己添加的。 end 和 _end 的地址&#xff0c;就是最终程序的堆的起始地址 要打印它们的话&#xff0c;一个样例程序在下面&#xff1a; …

【opencv】示例-asift.cpp 对两张图片之间进行仿射特征比对

#include <opencv2/core.hpp> // 包含OpenCV核心功能的头文件 #include <opencv2/imgproc.hpp> // 包含OpenCV图像处理功能的头文件 #include <opencv2/features2d.hpp> // 包含OpenCV特征检测相关功能的头文件 #include <opencv2/highgui.hpp> // 包含…

关于阿里云云数据库自动扩缩容和自动SQL优化的20道面试题

1. 请解释阿里云云数据库自动扩缩容的概念及其工作原理。 阿里云云数据库自动扩缩容是一种基于数据库实例的实时性能数据&#xff0c;能够发现流量异常并提供合理的数据库规格建议和磁盘容量建议的功能。其工作原理如下&#xff1a; 性能监控&#xff1a;系统会实时监控数据库…

Java线程亲和实战

环境&#xff1a;Linux version 5.4.0-1084-aws (builddlcy02-amd64-044) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #91~18.04.1-Ubuntu SMP Sun Aug 14 01:24:43 UTC 2022 JDK: 1.8.0_241 CPU分配是如何工作的&#xff1f; 如果您有或提供了一个&#xff0c;该库…

sqlmap(五)

一、进行文件读写操作 1.1 前提条件 高权限 目录有读写权限 secure_file_priv " " 1.2 测试目标 第一步&#xff1a;用抓包的方式获取请求测试站点的数据包 可以使用Burpsuite 第二步&#xff1a;将抓到的数据包&#xff0c;保存到sqlmap目录下的a.txt 第三步&am…

FPGA和ARM学习那个比较好

FPGA和ARM是两种不同的技术&#xff0c;具有不同的应用领域和学习难度。以下是对两者进行比较的一些建议&#xff1a; 1. 应用领域&#xff1a;FPGA主要用于数字电路设计和硬件加速器开发&#xff0c;可在实时系统、信号处理、嵌入式系统等方面发挥重要作用。ARM则是一种处理器…

C++的vector类(二):vector类的实际OJ应用

1、只出现一次的数字 2、杨辉三角 3、删除有序数组中的重复项 4、只出现一次的数字 II 5、只出现一次的数字 III 6、数组中出现次数超过一半的数字 7、电话号码的字母组合 ~over~

从FasterTransformer源码解读开始了解大模型(1.1)一个decoder-only的模型长啥样

从FasterTransformer源码解读开始了解大模型&#xff08;1.1&#xff09;一个decoder-only的模型长啥样 写在前面的话 对于一个没有接触过LLM的初学者来说&#xff0c;如果想要了解一个大模型的推理框架&#xff0c;首先应该知道大模型整个的工作原理是怎样的&#xff0c;知道…

了解自动化机器学习 AutoML

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 自动化机器学习&#xff08;AutoML&#xff09;概述 自动化机器学习&#xff08;AutoML&#xff09;旨在自动化机器学习模型的开发流程&#xff0c;通过简化或去除需要专业知识的复杂步骤&#xff0c;…

CSS面试题常用知识总结day03

大家好我是没钱的君子下流坯&#xff0c;用自己的话解释自己的知识 前端行业下坡路&#xff0c;甚至可说前端已死&#xff0c;我还想在前段行业在干下去&#xff0c;所以从新开始储备自己的知识。 从CSS——>Javascript——>VUE2——>Vuex、VueRouter、webpack——>…

Stale Diffusion、Drag Your Noise、PhysReaction、CityGaussian

本文首发于公众号&#xff1a;机器感知 Stale Diffusion、Drag Your Noise、PhysReaction、CityGaussian Drag Your Noise: Interactive Point-based Editing via Diffusion Semantic Propagation Point-based interactive editing serves as an essential tool to compleme…

vite打包失败 - out of memory

在做项目时&#xff0c;随着需求的不断增加&#xff0c;我们的代码文件会越来越大&#xff0c;但是在打包时&#xff0c;在 Node 中通过 JavaScript 使用内存的大小却是有限制的。于是&#xff0c;今天打算部署代码时&#xff0c;报错了: <--- JS stacktrace ---> JS st…

Nuxt 3 项目中配置 Tailwind CSS

官方文档&#xff1a;https://www.tailwindcss.cn/docs/guides/nuxtjs#standard 安装 Tailwind CSS 及其相关依赖 执行如下命令&#xff0c;在 Nuxt 项目中安装 Tailwind CSS 及其相关依赖 npm install -D tailwindcss postcss autoprefixerpnpm install -D tailwindcss post…

VUE必知必会

一、简介 Vue.js是一个流行的JavaScript框架&#xff0c;用于构建用户界面和单页应用程序&#xff08;SPA&#xff09;。自2014年由前Google工程师尤雨溪发布以来&#xff0c;Vue迅速获得了广泛的关注和使用&#xff0c;特别是在前端开发领域。 核心特性 响应式数据绑定&#…