C++20新特性的补充讲解
C++20 标志着 C++ 语言的一次重要更新,除了 Concepts、Ranges、协程等被广泛讨论的特性外,还有许多值得注意的改进。本文将详细探讨其他一些核心新特性,包括 constexpr
扩展、新增的 std::format
、std::span
、std::bit
操作、原子智能指针、char8_t
类型以及 lambda 表达式的改进等。通过这些特性,C++20 带来了更简洁、更高效的编程体验。
文章目录
- @[toc]
- 一、`constexpr` 扩展
- 示例
- 二、`std::format`:强大的字符串格式化
- 示例
- 三、`std::span`:安全的连续内存视图
- 示例
- 四、`std::bit` 操作库
- 示例
- 五、原子智能指针
- 示例
- 六、`char8_t` 类型
- 示例
- 七、lambda 表达式的改进
- 1. 捕获 `this` 的改进
- 2. 模板 lambda
- 八、扩展的`[[nodiscard]]`属性
- 示例
- 九、改进的`std::chrono`库
- 示例
- 十、其他改进
- 1. `std::source_location`
- 2. `std::stop_token` 和 `std::jthread`
- 3. 匿名结构体和联合体
- 总结
文章目录
- @[toc]
- 一、`constexpr` 扩展
- 示例
- 二、`std::format`:强大的字符串格式化
- 示例
- 三、`std::span`:安全的连续内存视图
- 示例
- 四、`std::bit` 操作库
- 示例
- 五、原子智能指针
- 示例
- 六、`char8_t` 类型
- 示例
- 七、lambda 表达式的改进
- 1. 捕获 `this` 的改进
- 2. 模板 lambda
- 八、扩展的`[[nodiscard]]`属性
- 示例
- 九、改进的`std::chrono`库
- 示例
- 十、其他改进
- 1. `std::source_location`
- 2. `std::stop_token` 和 `std::jthread`
- 3. 匿名结构体和联合体
- 总结
一、constexpr
扩展
在 C++20 中,constexpr
关键字得到了进一步扩展,使得更多的操作可以在编译期执行。这意味着我们可以在 constexpr
中使用更复杂的代码,包括 try-catch
异常处理、动态分配和更多的标准库函数,使编译时常量计算的范围大大增加。
示例
#include <array>
#include <iostream>constexpr int factorial(int n) {if (n <= 1) return 1;return n * factorial(n - 1);
}int main() {constexpr int result = factorial(5); // 在编译期计算std::cout << result << std::endl; // 输出:120return 0;
}
在这个例子中,我们利用 constexpr
计算阶乘函数 factorial
。在 C++20 中,这种递归计算不仅更加灵活,还可以在编译期完成,为程序提供了额外的性能优化空间。
二、std::format
:强大的字符串格式化
std::format
是 C++20 引入的一个重要新特性,类似于 Python 的 f-string
或者 printf
函数,提供了更现代、灵活的字符串格式化功能。std::format
使用占位符和格式说明符来简化字符串拼接操作,使代码更清晰。
示例
#include <format>
#include <iostream>int main() {int year = 2023;double pi = 3.14159;std::string formatted = std::format("The year is {} and Pi is {:.2f}.", year, pi);std::cout << formatted << std::endl; // 输出:The year is 2023 and Pi is 3.14.return 0;
}
这里,std::format
使用 {}
作为占位符,支持指定宽度、精度等格式化参数。相比传统的 sprintf
函数,std::format
更加类型安全、功能更强大,提升了代码的可读性和安全性。
三、std::span
:安全的连续内存视图
std::span
是一种轻量级的非拥有数据的容器视图,用于表示连续的内存块,例如数组或 std::vector
的某部分。std::span
提供了访问连续内存的方式,而不需要传递指针和大小参数,提高了接口的安全性和可读性。
示例
#include <span>
#include <iostream>void print(std::span<int> data) {for (int value : data) {std::cout << value << " ";}
}int main() {int arr[] = {1, 2, 3, 4, 5};print(arr); // 可以直接传入数组return 0;
}
std::span
的优势在于可以避免数组指针传递带来的边界不清问题,提供了更加一致和简洁的接口。它还可以与 std::vector
等容器结合使用,进一步增强代码的灵活性。
四、std::bit
操作库
C++20 新增了 std::bit
标准库,提供了一系列用于位操作的函数,包括按位旋转、按位计数等操作。这些操作对底层位操作有很大的帮助,简化了位处理的复杂度。
示例
#include <bit>
#include <iostream>int main() {unsigned int x = 0b0011'1100;// 位旋转操作unsigned int rotated = std::rotl(x, 2); // 左旋 2 位std::cout << "After left rotation: " << std::bitset<8>(rotated) << std::endl;// 计算 1 的数量int count = std::popcount(x);std::cout << "Number of 1s: " << count << std::endl;return 0;
}
这些位操作函数对需要处理位运算的程序员来说非常实用,提供了更高效、更简洁的位操作支持,适合于处理嵌入式系统和性能敏感的应用场景。
五、原子智能指针
C++20 引入了 std::atomic_shared_ptr
和 std::atomic_weak_ptr
,使得智能指针能够以原子的方式操作。这一改进简化了并发编程中智能指针的管理,保证了多线程环境下的指针操作安全。
示例
#include <atomic>
#include <iostream>
#include <memory>
#include <thread>std::atomic<std::shared_ptr<int>> atomic_ptr;void thread1() {auto ptr = std::make_shared<int>(42);atomic_ptr.store(ptr);
}void thread2() {auto ptr = atomic_ptr.load();if (ptr) {std::cout << "Value: " << *ptr << std::endl;}
}int main() {std::thread t1(thread1);std::thread t2(thread2);t1.join();t2.join();return 0;
}
原子智能指针的引入简化了多线程环境下共享资源的管理,确保了数据的线程安全,是并发编程中的一项重要改进。
六、char8_t
类型
C++20 引入了 char8_t
类型,用于表示 UTF-8 编码的字符。这一类型使得代码在处理多字节字符时更加清晰和安全,避免了传统 char
类型在编码上的模糊性。
示例
#include <iostream>void print_utf8(const char8_t* text) {while (*text) {std::cout << static_cast<char>(*text);text++;}
}int main() {const char8_t* text = u8"Hello, UTF-8!";print_utf8(text); // 输出:Hello, UTF-8!return 0;
}
char8_t
提供了更强的编码明确性,减少了因编码转换产生的错误和歧义,是现代应用程序处理 UTF-8 编码的理想选择。
七、lambda 表达式的改进
C++20 为 lambda 表达式带来了几项重要改进,包括捕获 this
指针的简化和 template
lambda 支持,使得 lambda 更加灵活易用。
1. 捕获 this
的改进
在 C++20 之前,lambda 捕获成员变量的方式较为繁琐。C++20 允许直接捕获 *this
,避免了冗长的捕获列表。
#include <iostream>struct MyClass {int value = 42;void show() {auto lambda = [*this] { std::cout << value << std::endl; };lambda();}
};int main() {MyClass obj;obj.show(); // 输出:42return 0;
}
2. 模板 lambda
模板 lambda 允许我们定义带模板参数的 lambda 表达式,适合泛型编程场景,使得 lambda 表达式更加灵活。
#include <iostream>int main() {auto add = []<typename T>(T a, T b) {return a + b;};std::cout << add(1, 2) << std::endl; // 输出:3std::cout << add(1.5, 2.5) << std::endl; // 输出:4.0return 0;
}
模板 lambda 为泛型编程提供了更简洁的写法,减少了冗长的函数模板定义,让代码更具表现力。
八、扩展的[[nodiscard]]
属性
C++20 扩展了 [[nodiscard]]
属性,允许对整个类型或函数标记 [[nodiscard]]
,表示返回值不可忽略。通过这一属性,可以避免意外忽略重要返回值引起的潜在错误。
示例
#include <iostream>[[nodiscard]] int compute_important_value() {return 42;
}int main() {compute_important_value(); // 警告:忽略了 `nodiscard` 返回值return 0;
}
[[nodiscard]]
属性提高了代码的健壮性,使得重要返回值不会被意外忽略。它适用于那些返回值不可忽略的函数,比如错误处理、资源分配等场景。通过 [[nodiscard]]
属性,C++20 能够进一步减少因忽略关键返回值导致的潜在问题。
九、改进的std::chrono
库
C++20 对 std::chrono
时间库进行了改进,添加了对历法和时区的支持。这些改进使得处理日期和时间更加方便,尤其是在处理跨时区和复杂日期计算的应用中。
示例
#include <iostream>
#include <chrono>
#include <format>int main() {using namespace std::chrono;// 获取当前的系统时间auto now = system_clock::now();// 格式化输出日期和时间std::cout << std::format("Current time: {:%Y-%m-%d %H:%M:%S}\n", now);// 计算未来的日期auto future_date = now + days(100);std::cout << std::format("100 days later: {:%Y-%m-%d}\n", future_date);return 0;
}
std::chrono
的改进使得日期和时间的处理更加直观,避免了开发者使用外部库来实现类似功能。通过新的时区支持,C++20 让时间计算和显示更加精确和方便。
十、其他改进
除了上面提到的主要特性,C++20 还包含了许多小而实用的改进:
1. std::source_location
std::source_location
允许获取源代码的位置(如文件名、行号和函数名),用于日志和调试信息的记录,非常适合用于调试和错误跟踪。
#include <iostream>
#include <source_location>void log(const std::string& message, const std::source_location& location = std::source_location::current()) {std::cout << "Log: " << message<< " (" << location.file_name() << ":" << location.line() << " in " << location.function_name() << ")\n";
}int main() {log("An example message");return 0;
}
2. std::stop_token
和 std::jthread
std::stop_token
和 std::jthread
简化了线程的停止机制,支持安全的线程中断。std::jthread
自动管理线程的生命周期,避免了线程资源泄漏。
#include <iostream>
#include <thread>
#include <chrono>
#include <stop_token>void task(std::stop_token stop_token) {while (!stop_token.stop_requested()) {std::cout << "Working...\n";std::this_thread::sleep_for(std::chrono::seconds(1));}std::cout << "Task stopped.\n";
}int main() {std::jthread worker(task); // 使用 jthread 运行线程std::this_thread::sleep_for(std::chrono::seconds(3));worker.request_stop(); // 请求线程停止return 0;
}
3. 匿名结构体和联合体
C++20 支持匿名结构体和联合体,允许在类中嵌套匿名的 struct
或 union
,从而简化代码结构。
#include <iostream>struct Point {union {struct {int x, y;};int coords[2];};
};int main() {Point p;p.x = 10;p.y = 20;std::cout << "Point x: " << p.coords[0] << ", y: " << p.coords[1] << std::endl;return 0;
}
匿名结构体和联合体在需要存储多个互斥数据时提供了更便捷的方式,使代码更加紧凑。
总结
C++20 是一次全面的更新,带来了 Concepts、Ranges、Coroutines 等重量级特性,同时通过 constexpr
扩展、std::format
、std::span
、原子智能指针、std::chrono
改进等大量优化,为开发者提供了更强大的工具链。这些特性不仅提升了 C++ 代码的安全性、性能和可读性,还使得开发体验更加便捷和高效。
通过这些新特性,C++20 不仅解决了长期以来的模板编程复杂性、多线程管理等问题,还引领了现代 C++ 向更加简洁、高效的方向发展。对于 C++ 开发者来说,学习和掌握这些新特性将大大提升编程效率,并为创建更具扩展性和可维护性的代码奠定基础。
相关文章:
C++20新特性的补充讲解
C20 标志着 C 语言的一次重要更新,除了 Concepts、Ranges、协程等被广泛讨论的特性外,还有许多值得注意的改进。本文将详细探讨其他一些核心新特性,包括 constexpr 扩展、新增的 std::format、std::span、std::bit 操作、原子智能指针、char8…...

uni-app移动端与PC端兼容预览PDF文件
过程遇到的问题 1、如果用的是最新的版本的pdfjs的话,就会报Promise.withResolvers 不是一个方法的错误,原因是Promise.withResolvers是ES15新特性,想了解可参考链接,这里的解决方案是将插件里的涉及到Promise.withResolvers的地…...
Elman 神经网络算法详解
Elman 神经网络算法详解 一、引言 Elman 神经网络作为一种经典的递归神经网络(RNN),在处理动态系统和时间序列数据方面具有独特的优势。它通过特殊的结构设计,能够有效地捕捉数据中的时间依赖关系,在语音识别、自然语…...
卓胜微嵌入式面试题及参考答案(2万字长文)
freeRTOS 任务是怎么调度的? 在 freeRTOS 中,任务调度主要是基于优先级的抢占式调度。每个任务都有一个优先级,系统会根据任务的优先级来决定哪个任务获得 CPU 的使用权。 当一个高优先级的任务准备运行,并且当前运行的任务优先级较低时,高优先级任务会抢占 CPU。例如,假…...

【Python】爬虫使用代理IP
1、代理池 IP 代理池可以理解为一个池子,里面装了很多代理IP。 池子里的IP是有生命周期的,它们将被定期验证,其中失效的将被从池子里面剔除池子里的ip是有补充渠道的,会有新的代理ip不断被加入池子中池子中的代理ip是可以被随机…...

金融机构-业务架构方案(高光版)
一、金融机构的设计架构 首先视角很重要,比如这样的战略视角,站得高、看得远。设计业务架构,一定要有战略高度和前瞻性。 二、什么样的架构更适合你们公司呢? 三、从架构着手,进行产品和服务创新性变革 四、具体如何设计业务架构呢?...
ubuntu内核切换network unclaimed 网卡丢失
现象一、 查网络的时候 提示只有lo network unclaimed wifi 本地局域网全部丢失 显卡丢失 解决思路 首先查看了 网卡类型 sudo lshw -C network 会显示使用的网卡 然后把这个网卡 去到realtek的官网去找驱动 驱动下下来发现debug提示 没有build目录 /libs/modules/6.8…...

【人工智能】揭秘可解释性AI(XAI):从原理到实战的终极指南
文章目录 开篇:AI的黑箱时代,你准备好揭开真相了吗?🔍什么是可解释性AI(XAI)?XAI的定义XAI的分类 可解释性AI的重要性与价值建立用户信任遵循法规和伦理发现和纠正模型偏见提高模型性能促进跨领…...

小面馆叫号取餐流程 佳易王面馆米线店点餐叫号管理系统操作教程
一、概述 【软件资源文件下载在文章最后】 小面馆叫号取餐流程 佳易王面馆米线店点餐叫号管理系统操作教程 点餐软件以其实用的功能和简便的操作,为小型餐饮店提供了高效的点餐管理解决方案,提高了工作效率和服务质量 点餐管理:支持电…...

图形 2.6 伽马校正
伽马校正 B站视频:图形 2.6 伽马校正 文章目录 伽马校正颜色空间传递函数 Gamma校正校正过程为什么需要校正?CRT与转换函数 为什么sRGB在Gamma 0.45空间? 人对亮度的敏感韦伯定律中灰值 线性工作流不在线性空间下进行渲染的问题统一到线性空…...

LLM - 计算 多模态大语言模型 的参数量(Qwen2-VL、Llama-3.1) 教程
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/143749468 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 影响 (…...

数据可视化这样做,汇报轻松拿捏(附免费好用可视化工具推荐)
一、数据可视化的定义 数据可视化是数据分析中重要的工作之一。在完成数据采集之后,通过可视化方式,将数据转化为美观且浅显易懂的统计图/表/视频,从而进一步解读数据背后隐藏的价值,这种方数据处理方式就叫做数据可视化。近些年…...
杂七杂八之基于JSON Web Token (JWT) 进行API认证和鉴权(Java版)
杂七杂八之基于JSON Web Token (JWT) 进行API认证和鉴权(Java版) 在现代Web应用和API开发中,JSON Web Token (JWT) 是一种广泛使用的认证和鉴权机制。JWT不仅简化了认证流程,还提供了安全的令牌传递方式,使得跨域认证…...

建设展示型网站企业渠道用户递达
展示型网站的主要作用便是作为企业线上门户平台、信息承载形式、拓客咨询窗口、服务/产品宣传订购、其它内容/个人形式呈现等,网站发展多年,现在依然是企业线上发展的主要工具之一且有建设的必要性。 谈及整体价格,自制、定制开发、SAAS系统…...

如何通过AB测试找到最适合的Yandex广告内容
想要在Yandex上找到最能吸引目标受众的广告内容,A/B测试是一个不可或缺的步骤。通过对比不同版本的广告,我们可以发现哪些元素最能引起用户的共鸣。首先,设计两个或多个广告版本,确保每个版本在标题、文案、图片等关键元素上有所不…...

AI写作(四)预训练语言模型:开启 AI 写作新时代(4/10)
一、预训练语言模型概述 预训练语言模型在自然语言处理领域占据着至关重要的地位。它以其卓越的语言理解和生成能力,成为众多自然语言处理任务的关键工具。 预训练语言模型的发展历程丰富而曲折。从早期的神经网络语言模型开始,逐渐发展到如今的大规…...

解决Anaconda出现CondaHTTPError: HTTP 000 CONNECTION FAILED for url
解决Anaconda出现CondaHTTPError: HTTP 000 CONNECTION FAILED for url 第一类情况 在anaconda创建新环境时,使用如下代码 conda create -n charts python3.7 错误原因: 默认镜像源访问速度过慢,会导致超时从而导致更新和下载失败。 解决方…...

员工绩效统计出现很多小数点,处理方法大全
1.直接通过数据库修改数据类型 譬如采用DECIMAL类型 2.float 降低小数点位数 3.php 采用round函数...

【启明智显分享】5G CPE为什么适合应用在连锁店中?
连锁门店需要5G CPE来满足其日益增长的网络需求,提升整体运营效率和竞争力。那么为什么5G CPE适合连锁店应用呢,小编为此做了整理,主要是基于以下几个方面的原因: 一、高效稳定的网络连接 1、高速数据传输: 5G CPE能…...

十大经典排序算法-希尔排序与归并排序
1、希尔排序 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 插入排序在对几乎已经排好序的数据操作时,效率高&…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...