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

嫌 OpenClaw 太重?ZeroClaw 重磅开源!

大家好,我是玄姐。 摘要:当 OpenClaw 的 Node.js 内存占用让你抓狂,当 Agent 的响应速度无法满足实时需求,是时候看看 Rust 带来的新选择了。ZeroClaw,一个 100% Rust 编写、极致轻量、高度模块化的 AI Agent 框架,正式开源。 过去的一个月里,OpenClaw(及其前身 Moltbot/Clawdbot)以其强大的生态和易用性,几乎成为了开源 AI Agent 的代名词。然而,随着大家在生产环境中通过 Node.js 运行越来越复杂的 Agent 工作流,一些问题也逐渐浮出水面: 资源消耗大:Node.js 运行时的内存占用在多 Agent 场景下显得捉襟见肘。

By Ne0inhk

ALVR终极配置指南:3步解决VR串流卡顿问题

ALVR终极配置指南:3步解决VR串流卡顿问题 【免费下载链接】ALVRALVR is an open source remote VR display for Gear VR and Oculus Go. With it, you can play SteamVR games in your standalone headset. 项目地址: https://gitcode.com/gh_mirrors/alv/ALVR ALVR作为开源VR远程显示解决方案,能够将PC端的SteamVR游戏流畅传输到Gear VR、Oculus Go/Quest等独立头显设备。本指南将带你从基础安装到高级优化,彻底解决VR串流中的卡顿和延迟问题。 入门指南:从零开始搭建ALVR环境 硬件要求检查清单 在开始配置之前,请确保你的设备满足以下基本要求: 设备类型最低配置推荐配置PC显卡NVIDIA

By Ne0inhk
1.5k stars!阿里开源 PageAgent:让 AI 直接“住进“你的网页,用自然语言操控一切!

1.5k stars!阿里开源 PageAgent:让 AI 直接“住进“你的网页,用自然语言操控一切!

阿里开源 PageAgent:让 AI 直接"住进"你的网页,用自然语言操控一切 不需要浏览器插件,不需要 Python,不需要截图——一行 JS,让你的网页秒变 AI 智能体。 一、先说痛点:Web 自动化为什么这么难? 如果你用过 Selenium、Playwright,或者最近流行的 browser-use,你一定遇到过这些头疼的问题: * 环境太重:得装 Python、headless 浏览器、各种依赖,部署复杂,维护成本高; * 依赖截图 + OCR:很多方案靠多模态模型"看图操作",慢、贵、还不准; * 权限门槛高:要控制浏览器,往往需要特殊权限甚至操作系统级别的访问; * 对现有产品改造成本大:

By Ne0inhk
AI Agent开发第86课-讲透知识图谱Neo4j在构建Agent时到底怎么用(一)

AI Agent开发第86课-讲透知识图谱Neo4j在构建Agent时到底怎么用(一)

前言 知识图谱常被误解为一堆实体和关系的静态集合,实则不然。它的本质是一种结构化的语义网络,用“实体-关系-实体”的三元组形式,刻画现实世界中对象之间的复杂关联。这种建模方式天然贴近人类认知逻辑——我们理解“苹果”不仅因其属性(红色、甜),更因它与“水果”“乔布斯”“iPhone”等概念存在上下位、创始人、品牌等不同语义关系。传统关系型数据库以表结构存储数据,在表达这类多跳、异构、动态的关系时显得力不从心,JOIN 操作成本随关联深度指数级增长。图数据库的出现正是为了解决这一根本矛盾。 Neo4j 作为主流图数据库代表,将数据直接建模为节点与关系,查询时沿着连接路径遍历,时间复杂度与路径长度相关,而非全表扫描。这使得在智能 Agent 构建中,当需要基于多层因果、上下文或隐含关联进行推理决策时,Neo4j 能提供毫秒级响应。笔者认为,Agent 的“智能”不仅体现在大模型的语言生成能力,更在于其能否基于可靠、可追溯的知识结构进行逻辑推演。知识图谱配合 Neo4j,

By Ne0inhk