C++11新特性(下)----《Hello C++ Wrold!》(26)--(C/C++)

C++11新特性(下)----《Hello C++ Wrold!》(26)--(C/C++)

文章目录

前言

在 C++11 标准带来的诸多革命性特性中,“简化代码编写” 与 “统一可调用对象管理” 是两大核心目标。lambda 表达式解决了传统仿函数 “定义繁琐、复用性低” 的痛点,让局部场景下的自定义逻辑(如排序规则、回调函数)能以更简洁的匿名函数形式实现;可变参数模板则打破了模板参数数量固定的限制,为 STL 容器(如emplace_back)和通用函数设计提供了灵活的参数处理能力;而 function 包装器与 bind 函数,则进一步整合了函数指针、仿函数、lambda 等不同类型的可调用对象,实现了统一管理与参数适配,甚至让可调用对象存储到容器中成为可能。

这些特性并非孤立存在 ——lambda 的底层依赖仿函数实现,可变参数模板为emplace系列接口提供了技术支撑,function 与 bind 则基于前两者的特性,解决了 “不同可调用对象类型不统一” 的问题。本文将从实际开发需求出发,先讲解 lambda 表达式的语法规则与捕获逻辑,再深入可变参数模板的展开方法与应用场景,最后通过 function 包装器与 bind 函数的实例,展示如何统一管理各类可调用对象、灵活调整参数顺序与固定参数值。

文中不仅会拆解易混淆的概念(如 lambda 的 mutable 修饰符作用、placeholders 占位符的使用规则),还会结合具体代码示例(如用 vector 存储 function 对象、用 bind 适配类成员函数),帮助读者理解这些特性的设计逻辑与实际价值。同时,文末的作业解析也将围绕 C++11 常见考点(如范围 for 的适用场景)展开,进一步巩固对标准特性的理解,为后续高效使用 C++11 进行开发打下基础。

lambda表达式

比如:一个类里面有很多成员变量,想对他们都进行排序,但是每次比较的逻辑不一样,而且还要每次都写一个类去比较,太麻烦了,所以就引入了lambda表达式

lambda表达式是局部的匿名的函数对象–所以sort填仿函数那里可以写这个

底层其实是用的仿函数实现的
这个表达式不存在重载这个说法哈

引申:auto f1 = (){}; 和auto f2 = (){}; f1和f2也不是同一类型 f1=f2的话会报错

也就是. lambda表达式之间不能相互赋值,即使看起来类型相同
这个表达式的格式:[捕捉列表](参数列表)(mutable)-> 返回值类型 { 函数体 }; 捕获列表的话可以捕获这个表达式所在域的局部变量--函数也可以捕捉哈 --全局域里的不用捕获也能用 --这种的强行捕获可能会报错 参数列表里面不传参的话,()也可以省了 这个mutable的话可以取消捕获列表里面东西默认的const性 但是在用该修饰符的时候,参数列表不能省略 --如果捕获的东西本来是const的话,加了mutable也变不了 注意:捕获列表默认是const的 ->返回值类型:这个一般可以不用写,编译器会推导 
关于捕获列表:(没用mutable的话,捕获的东西都不能被修改)

[var]:表示值传递方式捕捉变量var–var的类型会跟传递过来的一模一样

[=]:表示值传递方式捕获所有父作用域中的变量(包括this)

[&var]:表示引用传递捕捉变量var eg:[&x,&y]--这个跟取地址不要混了

[&]
:表示引用传递捕捉所有父作用域中的变量(包括this)

这里面的&=:如果是[&,x]那就只有x是值传递,其他都是引用

注意:捕捉列表不允许变量重复传递,否则就会导致编译错误[=,a]就不行,a捕获了两次
用法展示:
引申:可调用对象的四个存储方法:函数指针,仿函数,lambda表达式,用包装器搞到容器里面

可变参数模板

就是让模板参数可以是不确定的数目

其实日常自己写的话很少用的
template<class... Args>voidShowList(Args... args){} Args表示一个包含零个或多个类型的参数包 args也是参数包,里面可以是0或多个参数 ...是展开参数包的操作(放在参数包后面--除了模板参数声明那里) 但是这个参数包想知道里面的参数是啥的话比较困难--不支持eg:arg[1]这样 

展开参数包的方法

1.递归展开参数包

2.逗号表达式展开参数包

应用

假设有个日期类Date template<class... Args> Date*Create(Args... args){ Date* ret =newDate(args...);return ret;} 可以Date* p1 =Create(2025,9,7);这样来用 或者 Date d(2025,9,7); Date* p1 =Create(d);也行 
emplace_back有可变参数模板 push_back没用 emplace_back可以直接传零散的参数进去 但是push_back必须要先把零散的参数搞成临时对象再传进去 

包装器

fiction包装器

function包装器也叫作适配器 他需要头文件#include <functional>

作用:比如:

并且包装器可以让可调用对象存储到容器中去了
用法: function的类模板原型:template<classT> function;//这是模板的声明template<classRet,class... Args>classfunction<Ret(Args...)>; Ret: 被调用函数的返回类型 Args…:被调用函数的形参 使用:doublef(double i){return i /2;}structFunctor{doubleoperator()(double d){return d /3;}}; vector<function<double(double)>> v ={ f,[](double d)->double{return d /4;},Functor()}; 第一个double是返回值类型 第二个double是形参类型--两个double类型的形参的话就写(double,double)
用法还有eg: map<string,function<int(int)>> map1 ={{"a",[](int x){return x;}},{"y",[](int x){return x+1;}}}; 用的话就:int x =0;int a = map1["a"](x);//注意理解map1["a"]取出包装器.....

bind函数

这个的头文件也是#include <functional>

bind
是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表

这个的作用也就是把参数的顺序改了+可以固定一些参数的值
这里固定参数的值跟直接给缺省值的比较:

缺省值只能给固定的参数一个固定值

这里就不一样了
用法: 对于普通的函数:doublePlus(int a,int b,double rate){return(a + b)* rate;} function<double(int,int)> Plus1 =bind(Plus, placeholders::_2, placeholders::_1,4.0); 这个的话就是rate固定是4.0 然后Plus1(9,8) 这里的placeholders::_1表示的是(9,8)里面的9然后会传给b这样 如果想固定的值在中间的话 eg:doublePlus(int a,double rate,int b){return(a + b)* rate;} function<double(int,int)> Plus1 =bind(Plus, placeholders::_2,4.0,placeholders::_1);Plus1(9,8);--8最终给了a 这个依旧是_1,_2这样的哈 
用法: 对于类里面的成员函数的话: 如果函数是静态的,那到没啥区别(但是记得加上类域) 如果函数不是静态的: 函数后面要跟上这个对象或者对象的指针才行 --函数是静态的话,可以加那个也可以不加 eg:classSubType{public:intsub(int a,int b){return a - b;}}; SubType st; function<double(int,int)> Sub2 =bind(&SubType::sub,&st, placeholders::_1, placeholders::_2,3); function<double(int,int)> Sub2 =bind(&SubType::sub, st, placeholders::_1, placeholders::_2,3); function<double(int,int)> Sub3 =bind(&SubType::sub,SubType(), placeholders::_1, placeholders::_2,3);//这里用的是匿名对象 引申:类里面的函数在外面用的时候必须要到类域里面去找才行 

作业部分

在这里插入图片描述
下面关于范围for说法错误的是(C) A.范围for可以直接应用在数组上 B.对于STL提供的所有容器,均可以使用范围for依次访问器元素 C.使用范围for操作stack,可以简化代码 //上面说的是容器,但是stack是容器适配器 D.对于自定义类型,想要支持范围for,必须提供begin和end迭代器 E.范围for编译器最终是将其转化为迭代器来进行处理的 
在这里插入图片描述

Read more

web前端JS—基本语法

一、引入方式 1、内部脚本:将代码定义在HTML页面里面 * 将JS定义在<script></script>之间 * 可以在html里面的任意位置放置任意数量的<script></script> * 一般放置在<body>元素的底部,改善显示速度 <script> console.log('页面加载时执行'); function localFunction() { return '内部函数'; } </script> 2、外部脚本:额外定义一个.js文件,引入到HTML里面 * 只能包含js文件,不包含&

By Ne0inhk
Spring Web MVC 入门秘籍:从概念到实践的快速通道(上)

Spring Web MVC 入门秘籍:从概念到实践的快速通道(上)

个人主页:♡喜欢做梦 欢迎  👍点赞  ➕关注  ❤️收藏  💬评论 目录 一、什么是Spring Web MVC? 1.定义 2.关于MVC 2.1什么是MVC? 二、学习Sring MVC 1.项目准备 2.@RestController注解的介绍 3.@RequestMapping注解 1.@RequestMapping只用在类上(相当于“只给文件夹起名,不给文件起名”) 2.@RequestMapping只用在方法上(相当于“只给文件起名,不给文件夹起名”) 3.@RequestMapping用在类和方法上(相当于给文件夹和文件都取名) 三、Postman 1.什么是Postman? 2.关于API 3.传参介绍 1.普通传参:

By Ne0inhk
【前端实战】Axios 错误处理的设计与进阶封装,实现网络层面的数据与状态解耦

【前端实战】Axios 错误处理的设计与进阶封装,实现网络层面的数据与状态解耦

目录 【前端实战】Axios 错误处理的设计与进阶封装,实现网络层面的数据与状态解耦 一、为什么网络错误处理一定要下沉到 Axios 层 二、Axios 拦截器 interceptors 1、拦截器的基础应用 2、错误分级和策略映射的设计 3、错误对象标准化 三、结语         作者:watermelo37         ZEEKLOG优质创作者、华为云云享专家、阿里云专家博主、腾讯云“创作之星”特邀作者、火山KOL、支付宝合作作者,全平台博客昵称watermelo37。         一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、Python、LLM均有涉猎。 --------------------------------------------------------------------- 温柔地对待温柔的人,包容的三观就是最大的温柔。 --------------------------------------------------------------------- 【前

By Ne0inhk

OpenClaw Skills扩展:nanobot通过webhook对接钉钉/飞书,实现跨平台消息同步

OpenClaw Skills扩展:nanobot通过webhook对接钉钉/飞书,实现跨平台消息同步 1. nanobot简介 nanobot是一款受OpenClaw启发的超轻量级个人人工智能助手,仅需约4000行代码即可提供核心代理功能。相比传统方案,代码量减少了99%,但功能依然强大。 这个轻量级助手内置了vllm部署的Qwen3-4B-Instruct-2507模型,使用chainlit进行推理交互。最吸引人的是,你可以轻松配置它作为QQ聊天机器人使用,或者通过webhook对接企业通讯工具如钉钉和飞书。 2. 基础环境验证 2.1 检查模型服务状态 在开始扩展功能前,我们需要确认基础服务运行正常。通过以下命令检查模型部署状态: cat /root/workspace/llm.log 如果看到服务启动成功的日志信息,说明模型已准备就绪。常见的成功标志包括"Model loaded successfully"或"Service started on port xxxx"等提示。 2.2 测试基础问答功能

By Ne0inhk