news 2026/10/1 21:33:10

【C++进阶】C++ 11(下)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【C++进阶】C++ 11(下)

目录

1 可变参数模板

2 emplace 系列接口

3 C++11 类新语法:default、delete

4 lambda 表达式

捕获规则

5 std::function 包装器

6 std::bind 适配器

小结


1 可变参数模板

C++11 支持可变参数模板,使用...代表参数包。分为模板参数包、函数参数包。

template<class ...Args> void Print(Args... args) { cout << sizeof...(args) << endl; // sizeof... 获取参数包中参数个数 }
  • Args...模板参数包;args...函数参数包。
  • sizeof...(args):编译期拿到参数包里面参数总个数。

参数包不能用 for 循环遍历,只能通过编译期递归展开。

递归展开示例:

#include<iostream> #include<string> using namespace std; //递归终止,参数包为空 void ShowList() { cout << endl; } template<class T, class ...Args> void ShowList(T x, Args... args) { cout << x << " "; ShowList(args...); // 剥掉第一个参数,剩下继续递归 } template<class ...Args> void Print(Args... args) { ShowList(args...); } int main() { Print(); Print(1); Print(1, string("hello")); Print(1.1, 2, "abc"); return 0; }

原理:编译阶段实例化出多份重载函数,不是运行时解析参数。

2 emplace 系列接口

容器新增emplace_back / emplace,接收可变参数包。

  • push_back:需要已经构造完成对象,再拷贝 / 移动进入容器;
  • emplace_back(Args&&... args):直接在容器结点内存上构造对象,不需要生成临时对象。

底层:可变参数包 + 完美转发std::forward<Args>(args)...,把参数转发给结点的构造函数。

示例 list 模拟结点:

template<class T> struct ListNode { T _data; ListNode<T>* _prev; ListNode<T>* _next; //支持可变参数直接构造data template<class... Args> ListNode(Args&&... args) :_data(std::forward<Args>(args)...) {} };

调用示例:

list<pair<string,int>> lt; lt.emplace_back("苹果",1); //直接传给pair构造,不用手动构造pair临时对象

3 C++11 类新语法:default、delete

C++98 类 6 个默认成员:

  1. 构造函数
  2. 拷贝构造
  3. 拷贝赋值重载
  4. 析构函数
  5. 取地址operator&
  6. const 取地址operator&

C++11 新增两个默认成员函数:移动构造、移动赋值。

规则:

  1. 没有自己写析构、拷贝构造、拷贝赋值,编译器才会自动生成默认移动构造 / 移动赋值。
  2. =default:强制让编译器生成默认版本函数。
  3. =delete:删除函数,禁止调用该函数(C++98 时代把函数放 private 实现同样效果)。

示例:

class Person { public: Person(const char* name = "", int age = 0){} Person(const Person& p){} Person(Person&& p) = default; //强制生成默认移动构造 Person& operator=(Person&& p) = default; Person& operator=(const Person& p) = delete; //删除拷贝赋值,禁止使用 };

另外 C++11 支持类内成员变量直接初始化缺省值,给初始化列表提供默认值。

4 lambda 表达式

lambda 本质:编译器自动生成匿名仿函数类。 完整语法:

[捕获列表](参数列表) -> 返回类型 {函数体};
  1. []捕获列表,不可省略;
  2. ()参数列表,无参数可以省略;
  3. ->返回类型追踪返回类型,可以省略,编译器自动推导;
  4. {}函数体,不可省略。
捕获规则

表格

写法含义
[x]值捕获,拷贝一份,默认 const,不能修改
[&x]引用捕获,直接使用外部变量本体,可以修改
[=]隐式值捕获:用到的变量全部值捕获
[&]隐式引用捕获:用到的变量全部引用捕获
[=, &a]其它值捕获,a 引用捕获
[&, a]其它引用捕获,a 值捕获
  • mutable:加在参数括号后面,取消值捕获变量的 const 属性,可以修改拷贝副本,不会影响外部实参。
  • 全局变量、静态局部变量不需要捕获,可以直接使用;lambda 写在全局域,捕获列表必须为空。
#include<iostream> #include<vector> #include<algorithm> #include<string> using namespace std; struct Goods { string _name; double _price; int _evaluate; Goods(const char* str, double price, int evaluate) :_name(str),_price(price),_evaluate(evaluate) {} }; int main() { vector<Goods> v = { {"苹果", 2.1, 5}, {"香蕉",3,4},{"橙子",2.2,3},{"菠萝",1.5,4} }; sort(v.begin(),v.end(),[](const Goods& g1,const Goods& g2){ return g1._price < g2._price; }); return 0; }

lambda 底层原理:编译器生成一个仿函数类,捕获的变量变成类的成员;调用 lambda 等价调用仿函数operator()。

5 std::function 包装器

头文件<functional>。std::function<Ret(Args...)>:统一包装各类可调用对象:普通函数、函数指针、仿函数、lambda 表达式、bind 返回对象。 解决不同可调用对象类型不一样,无法统一保存的问题。 如果function对象没有包装目标,调用会抛出bad_function_call异常。

#include<functional> #include<iostream> using namespace std; int f(int a,int b) { return a+b; } struct Functor { int operator()(int a,int b) { return a+b; } }; int main() { function<int(int,int)> f1 = f; function<int(int,int)> f2 = Functor(); function<int(int,int)> f3 = [](int a,int b){return a+b;}; cout << f1(1,2) << endl; cout << f2(1,2) << endl; cout << f3(1,2) << endl; return 0; }

6 std::bind 适配器

头文件<functional>;bind 是函数适配器,包装可调用对象,可以:

  1. 绑定固定参数;
  2. 调整参数顺序; 占位符_1 _2 _3定义在std::placeholders命名空间。
#include<functional> #include<iostream> using namespace std; using placeholders::_1; using placeholders::_2; int Sub(int a,int b) { return (a-b)*10; } int main() { auto sub1 = bind(Sub,_1,_2); cout << sub1(10,5) << endl; auto sub2 = bind(Sub,_2,_1); //交换参数顺序 cout << sub2(10,5) << endl; auto sub3 = bind(Sub,100,_1); //第一个参数固定100 cout << sub3(5) << endl; return 0; }

小结

  1. 可变参数模板依靠编译递归展开参数包,sizeof...(args)拿到参数数量;emplace依靠可变参数 + 完美转发直接在容器内存构造对象。
  2. =default强制生成编译器默认函数;=delete删除函数,禁止调用。C++11 新增移动构造、移动赋值两个默认成员。
  3. lambda 是编译器生成匿名仿函数,掌握捕获列表、mutable;适合算法 sort 等场景写临时逻辑。
  4. std::function统一包装不同类型可调用对象;std::bind做参数绑定、顺序调整适配器。

后续 C++11 其余特性:智能指针、unordered 哈希容器、范围 for、override/final、string_view 等属于其他章节。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 21:32:16

聚合增长GEO靠谱吗,技术实力与创新能力如何

当AI开始替客户做决定&#xff0c;你的品牌被看见了吗深夜十一点&#xff0c;苏州一家机械制造企业的老板还坐在办公室里。他刚试着在豆包里输入工业撕碎机哪家厂商实力强&#xff0c;屏幕上给出的推荐名单里&#xff0c;没有自己的公司。可他分明记得&#xff0c;五年前&#…

作者头像 李华
网站建设 2026/10/1 21:30:03

汽车索赔工具怎么搭?账房+改善引擎双系统讲透

汽车索赔工具怎么搭&#xff1f;账房改善引擎双系统讲透本文节选自新书 《汽车Tier1供应商售后全生命周期管理》第5章 核心活动&#xff1a;索赔管理&#xff08;5.10 索赔工具&#xff09;。作者基于一线 SQE&#xff08;供应商质量工程师&#xff09;视角的实战总结&#xf…

作者头像 李华
网站建设 2026/10/1 21:29:32

第 8 天 · 进阶提示词:思维链 / 少样本 / 角色扮演

第 8 天 进阶提示词&#xff1a;思维链 / 少样本 / 角色扮演 &#x1f680; &#x1f4a1; 今日引入 同一个问题&#xff0c;我换个说法问 AI&#xff0c;答案质量能差出一截。一开始我觉得挺邪门&#xff0c;后来摸清了规律——差别基本在我有没有把话说清楚&#xff0c;跟 A…

作者头像 李华
网站建设 2026/10/1 21:29:00

LinkSwift:8 大网盘直链下载,新手 10 分钟跑通

LinkSwift&#xff1a;8 大网盘直链下载&#xff0c;新手 10 分钟跑通 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / …

作者头像 李华