当前位置: 首页 > news >正文

C++17新特性

1、折叠表达式

c++17中引入了折叠表达式,主要是方便模版编程,分为左右折叠。
折叠表达式的本质是对参数包进行「二元运算符折叠」,将参数包中的元素通过指定运算符依次结合,最终得到一个单一值。
语法

类型语法格式说明
一元左折叠( … op pack )从左到右结合:((pack1 op pack2) op pack3) …
一元右折叠( pack op … )从右到左结合:(pack1 op (pack2 op pack3)) …
二元左折叠(带初始值)( init op … op pack )初始值参与左折叠:(((init op pack1) op pack2) op pack3) …
二元右折叠(带初始值)( pack op … op init )初始值参与右折叠:(pack1 op (pack2 op (pack3 op init))) …

eg:
一元折叠

#include<iostream>// 模板函数,接收任意数量的整数参数template<typename...T>autosum(T...args){// 一元左折叠:((arg1 + arg2) + arg3) + ...return(...+args);}intmain(){std::cout<<sum(1,2,3,4)<<std::endl;// 输出:10std::cout<<sum(10,20)<<std::endl;// 输出:30// 注意:参数包不能为空(一元折叠要求至少一个元素)// std::cout << sum() << std::endl; // 编译错误!return0;}

二元折叠

#include<iostream>template<typename...T>autosum(T...args){// 二元右折叠:arg1 + (arg2 + (arg3 + 0))// 初始值0,空参数包时返回0return(args+...+0);}intmain(){std::cout<<sum()<<std::endl;// 输出:0(空参数包)std::cout<<sum(1,2,3)<<std::endl;// 输出:6return0;}

2、类模版参数推导

类模板实例化时,可以不必显式指定类型,前提是保证类型可以推导

#include<iostream>usingnamespacestd;template<classT>classClassTest{public:ClassTest(T,T){};};intmain(){autoy=newClassTest{100,200};// 分配的类型是 ClassTest<int>return0;}

3、auto 占位的非类型模板形参

#include<iostream>usingnamespacestd;template<autoT>voidfunc1(){cout<<T<<endl;}intmain(){func1<100>();//func1<int>();return0;}

4、编译期constexpr if语句

#include<iostream>usingnamespacestd;template<boolok>constexprvoidfunc2(){//在编译期进行判断,if和else语句不生成代码ifconstexpr(ok==true){//当ok为true时,下面的else块不生成汇编代码cout<<"ok"<<endl;}else{//当ok为false时,上面的if块不生成汇编代码cout<<"not ok"<<endl;}}intmain(){func2<true>();//输出ok,并且汇编代码中只有 cout << "ok" << endl;func2<false>();//输出not ok,并且汇编代码中只有 cout << "not ok" << endl; return 0;}

5、inline变量

扩展的inline用法,使得可以在头文件或者类内初始化静态成员变量

// mycode.hinlineintvalue=100;// mycode.cppclassAAA{inlinestaticintvalue2=200;};

6、结构化绑定

结构化绑定(Structured Bindings)核心作用是一次性将复合类型(如结构体、数组、std::pair/tuple)的多个成员 / 元素绑定到多个变量上,避免手动逐个提取成员,让代码更简洁、易读。

  1. 绑定数组
#include<iostream>usingnamespacestd;intmain(){intarr[]={10,20,30};// 绑定数组的3个元素到a、b、cauto[a,b,c]=arr;cout<<a<<", "<<b<<", "<<c<<endl;// 输出:10, 20, 30// 注意:默认是值拷贝,修改a不会影响原数组a=100;cout<<arr[0]<<endl;// 输出:10(原数组未变)// 用引用绑定,修改会影响原数组auto&[x,y,z]=arr;x=100;cout<<arr[0]<<endl;// 输出:100(原数组被修改)return0;}
  1. 绑定简单结构体/类(要求结构体的所有非静态成员都是公有(private/protected 成员无法绑定))
#include<iostream>#include<string>usingnamespacestd;// 简单结构体(所有成员公有)structPerson{string name;intage;doubleheight;};intmain(){Person p{"Alice",25,1.65};// 绑定结构体的3个成员到name、age、heightauto[name,age,height]=p;cout<<"姓名:"<<name<<",年龄:"<<age<<",身高:"<<height<<endl;// const 引用绑定(避免拷贝,且禁止修改)constauto&[n,a,h]=p;// n = "Bob"; // 编译错误:const引用不可修改return0;}
  1. 绑定 std::pair/std::tuple(最常用场景)
    STL 中 std::pair(如 map 的键值对)、std::tuple 是结构化绑定的高频使用场景
#include<iostream>#include<tuple>#include<map>#include<string>usingnamespacestd;intmain(){// 1. 绑定std::pair(map的元素是pair)map<string,int>score_map={{"Math",90},{"English",85}};// 遍历map,绑定键值对到key和valuefor(constauto&[key,value]:score_map){cout<<key<<":"<<value<<endl;}// 2. 绑定std::tupletuple<string,int,double>t("Tom",30,1.75);auto[name,age,height]=t;cout<<"Tuple:"<<name<<", "<<age<<", "<<height<<endl;return0;}
  1. 绑定返回值(函数返回复合类型)
#include<iostream>#include<tuple>usingnamespacestd;// 函数返回多个值(tuple)tuple<int,string,double>get_student_info(){return{101,"zxp",99.9};}intmain(){// 直接绑定返回值的三个元素auto[id,name,score]=get_student_info();cout<<"学号:"<<id<<",姓名:"<<name<<",分数:"<<score<<endl;return0;}

7、lambda表达式捕获 *this

  1. 捕获this:lambda 拿到对象的指针(引用),多线程中若原对象已销毁,lambda 访问成员变量会触发未定义行为;
  2. C++17 捕获*this:lambda 直接拷贝整个对象(捕获副本),不受原对象生命周期影响,默认只能读、无法修改原对象(修改的是副本)。
#include<iostream>#include<thread>usingnamespacestd;classTest{public:intnum=10;voidfunc(){// 1. 捕获this:指向原对象,原对象销毁后访问num会出错autolambda1=[this](){cout<<this->num<<endl;// 依赖原对象存活};// 2. C++17捕获*this:拷贝对象副本,原对象销毁也不影响autolambda2=[*this](){cout<<this->num<<endl;// 访问的是副本的num};// 模拟多线程场景(仅示例,实际需注意线程生命周期)threadt1(lambda1);threadt2(lambda2);t1.detach();// 若Test对象提前析构,t1访问num是未定义行为t2.detach();// t2访问的是副本,安全}};intmain(){{Test t;t.func();// 函数执行完后,t会被销毁}return0;}

8、__has_include

跨平台项目需要考虑不同平台编译器的实现,使用__has_include可以判断当前环境下是否存在某个头文件。

intmain(){#if__has_include("iostream")cout<<"iostream exist."<<endl;#endif#if__has_include(<cmath>)cout<<"<cmath> exist."<<endl;#endifreturn0;}

9、std::filesystem

常用函数
std::filesystem::exists(const path& pval):用于判断path是否存在
std::filesystem::copy(const path& from, const path& to):目录复制
std::filesystem::absolute(const path& pval, const path& base = current_path()):获取相对于base的绝对路径
std::filesystem::create_directory(const path& pval):当目录不存在时创建目录
std::filesystem::create_directories(const path& pval):形如/a/b/c这样的,如果都不存在,创建目录结构
std::filesystem::file_size(const path& pval):返回目录的大小

10、std::string_view

C++ 中char*转std::string会触发内存拷贝(调用拷贝构造),即便只读操作也会产生不必要的性能损耗;C++17 新增std::string_view,仅作为char*/std::string的「只读视图」,不拷贝内存,仅保留字符串的指针和长度,只读不可写,优化了只读场景下的内存开销。

#include<string_view>#include<string>usingnamespacestd;voidread_str(constchar*cstr){// string:拷贝内存,性能损耗string s=cstr;// string_view:仅视图,无内存拷贝,只读string_view sv=cstr;}

11、std::optional

C / 早期 C++ 用T*指针(NULL/nullptr)表示 “有值 / 无值”;C++17 引入std::optional<>,以类型安全的方式封装 “值存在 / 不存在” 的语义,无需依赖指针,通过内置标志位标记值是否有效。

#include<optional>usingnamespacestd;// 可选的int值:有值则存数值,无值则为空optional<int>get_value(boolhas_val){if(has_val)return10;return{};// 无值状态}

12、std::variant

C++17 的std::variant是增强版union,支持存储复合类型,同一时间仅能保存一种类型的值;可通过index()获取当前值对应模板参数的索引(从 0 开始),或用holds_alternative<T>(v)判断当前值是否为类型T。

#include<variant>#include<iostream>usingnamespacestd;intmain(){variant<int,string,double>v="hello";cout<<v.index()<<endl;// 输出1(对应string,索引从0开始)cout<<boolalpha<<holds_alternative<string>(v)<<endl;// 输出truereturn0;}
http://www.jsqmd.com/news/472736/

相关文章:

  • 基于WOA鲸鱼优化的LSTM长短记忆网络模型的文本分类算法matlab仿真
  • 分⽀和循环:C语言的脊柱
  • 《HelloGitHub》第 期
  • 【优化部署】基于matlab果蝇算法改进虚拟力融合算法无线传感器网络节点部署【含Matlab源码 15143期】
  • R 基础运算
  • 螺旋矩阵总结
  • 2.2.1 - 3D图搜索算法(以A*为例) - Python运动规划库教程(Python Motion Planning)
  • Mysql安装测试--初入心得
  • Flutter 三方库 async_recursion 的鸿蒙化适配指南 - 稳健的异步递归治理,征服鸿蒙深层数据结构
  • ArkClaw让“养虾”更安全!火山引擎AI助手安全解决方案全面升级
  • 数据结构STL库(从入门到精通,适合小白)
  • 记一次 .NET 某放射治疗光学定位软件 卡死分析
  • 从通用Agent到领域Agent:技术原理与演进路径
  • 人工智能之数学基础:全微分的介绍
  • 【快速见刊】第二届生态环境保护、环境监测与修复国际学术会议(EPEMR 2026)
  • Jvm和垃圾回收精讲
  • 基于 ESP32S3 的 LVGL 9.4 图形库移植与 UI 开发实践分享(课程作业)
  • 鸿蒙常见问题分析三十三:如何解决Column子组件超出容器边界
  • OJ50 51 52
  • Leecode 18. 四数之和
  • 2026商家寄件价格避坑指南:5个省钱雷区别再踩!
  • SQL-存储引擎
  • Flutter 三方库 argos_translator_offline 的鸿蒙化适配指南 - 让机器翻译回归“端侧隔离”,打造鸿蒙应用专家级的离线多语言 AI 治理中台
  • 盘点10大主流AI Agent框架(非常详细),多智能体技术从入门到精通,收藏这一篇就够了!
  • 基于 Java + SpringBoot + Vue + MySQL 的游戏账号交易系统实战指南
  • 《MPMLS》 2026.3.12
  • 【Day4】
  • 推荐斯坦福计算机课程CS146S:当代软件工程师
  • 深度剖析DbContext的ChangeTracker:Entity状态管理与数据持久化关键
  • JMM——Java内存模型简介