C++20 是一个重大的更新版本,引入了许多革命性的特性,显著提升了语言的表达能力、类型安全性和开发效率。本文将详细介绍 C++20 的主要新特性,并提供丰富的代码示例。
目录
- 目录
- [🧠 一、核心语言特性](#🧠 一、核心语言特性 "#-%E4%B8%80%E6%A0%B8%E5%BF%83%E8%AF%AD%E8%A8%80%E7%89%B9%E6%80%A7")
- [模块 (Modules)](#模块 (Modules) "#%E6%A8%A1%E5%9D%97-modules")
- [概念 (Concepts)](#概念 (Concepts) "#%E6%A6%82%E5%BF%B5-concepts")
- [协程 (Coroutines)](#协程 (Coroutines) "#%E5%8D%8F%E7%A8%8B-coroutines")
- 三向比较(飞船运算符)
- [指定初始化 (Designated Initializers)](#指定初始化 (Designated Initializers) "#%E6%8C%87%E5%AE%9A%E5%88%9D%E5%A7%8B%E5%8C%96-designated-initializers")
- [范围 for 循环中的初始化语句](#范围 for 循环中的初始化语句 "#%E8%8C%83%E5%9B%B4-for-%E5%BE%AA%E7%8E%AF%E4%B8%AD%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96%E8%AF%AD%E5%8F%A5")
- [[[likely]] 和 [[unlikely]] 属性](#[[likely]] 和 [[unlikely]] 属性 "#likely-%E5%92%8C-unlikely-%E5%B1%9E%E6%80%A7")
- [constexpr 增强](#constexpr 增强 "#constexpr-%E5%A2%9E%E5%BC%BA")
- [using enum 声明](#using enum 声明 "#using-enum-%E5%A3%B0%E6%98%8E")
- 其他语言特性
- [📚 二、标准库特性](#📚 二、标准库特性 "#-%E4%BA%8C%E6%A0%87%E5%87%86%E5%BA%93%E7%89%B9%E6%80%A7")
- [1. 范围库 (Ranges Library)](#1. 范围库 (Ranges Library) "#1-%E8%8C%83%E5%9B%B4%E5%BA%93-ranges-library")
- [2. std::format 格式化库](#2. std::format 格式化库 "#2-stdformat-%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%BA%93")
- [3. std::span](#3. std::span "#3-stdspan")
- [4. std::jthread (协作式中断线程)](#4. std::jthread (协作式中断线程) "#4-stdjthread-%E5%8D%8F%E4%BD%9C%E5%BC%8F%E4%B8%AD%E6%96%AD%E7%BA%BF%E7%A8%8B")
- [🚀 总结](#🚀 总结 "#-%E6%80%BB%E7%BB%93")
🧠 一、核心语言特性
模块 (Modules)
目标: 取代传统的头文件(#include
)机制,解决头文件包含导致的编译速度慢、宏污染、循环依赖等问题。
机制: 将代码划分为模块接口单元(.ixx
, .cppm
)和模块实现单元(.cpp
)。接口单元使用 export module ModuleName;
导出声明;消费者使用 import ModuleName;
导入。
代码示例:
cpp
// math_utils.ixx - 模块接口单元
export module math_utils;
// 导出函数声明
export int add(int a, int b);
export int multiply(int a, int b);
// 导出类
export class Calculator {
public:
int calculate(int a, int b, char op);
private:
int internal_helper(int x); // 不导出,外部不可见
};
// 内部使用的函数,不导出
int internal_function() {
return 42;
}
cpp
// math_utils.cpp - 模块实现单元
module math_utils;
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
int Calculator::calculate(int a, int b, char op) {
switch(op) {
case '+': return add(a, b);
case '*': return multiply(a, b);
default: return 0;
}
}
int Calculator::internal_helper(int x) {
return x + internal_function();
}
cpp
// main.cpp - 使用模块
import math_utils;
#include <iostream>
int main() {
Calculator calc;
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
std::cout << "3 * 4 = " << calc.calculate(3, 4, '*') << std::endl;
// internal_function() 不可访问 - 编译错误
// auto x = internal_function();
return 0;
}
优点: 显著加快编译速度(接口只编译一次)、强封装性(内部细节不暴露)、避免名称冲突、更清晰的代码组织。
概念 (Concepts)
目标: 为模板编程(尤其是泛型编程)提供强大的类型约束机制,使模板错误信息更清晰易懂,并支持基于概念的函数重载。
机制: 使用 concept
关键字定义对模板参数的要求(一组约束)。在模板参数列表或函数声明中使用 requires
子句或简写语法来应用概念。
代码示例:
cpp
#include <concepts>
#include <iostream>
#include <vector>
#include <string>
// 1. 定义自定义概念
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
template<typename T>
concept Printable = requires(T t) {
std::cout << t; // 要求类型T可以输出到cout
};
template<typename T>
concept Container = requires(T t) {
t.begin(); // 要求有begin()方法
t.end(); // 要求有end()方法
t.size(); // 要求有size()方法
};
// 2. 使用概念约束模板参数
// 方式1:requires子句
template<typename T>
requires Numeric<T>
T add(T a, T b) {
return a + b;
}
// 方式2:简写语法
template<Numeric T>
T multiply(T a, T b) {
return a * b;
}
// 方式3:概念作为模板参数
auto divide(Numeric auto a, Numeric auto b) {
return a / b;
}
// 3. 复合概念约束
template<typename T>
requires Printable<T> && Container<T>
void print_container(const T& container) {
std::cout << "Container contents: ";
for (const auto& item : container) {
std::cout << item << " ";
}
std::cout << std::endl;
}
// 4. 基于概念的函数重载
template<std::integral T>
void process(T value) {
std::cout << "Processing integer: " << value << std::endl;
}
template<std::floating_point T>
void process(T value) {
std::cout << "Processing float: " << value << std::endl;
}
template<typename T>
requires (!std::integral<T> && !std::floating_point<T>)
void process(T value) {
std::cout << "Processing other type" << std::endl;
}
// 5. 更复杂的概念定义
template<typename T>
concept Comparable = requires(T a, T b) {
{ a < b } -> std::convertible_to<bool>;
{ a > b } -> std::convertible_to<bool>;
{ a == b } -> std::convertible_to<bool>;
};
template<Comparable T>
T max_value(T a, T b) {
return (a > b) ? a : b;
}
int main() {
// 数值运算
std::cout << add(3, 4) << std::endl; // OK: int是Numeric
std::cout << multiply(3.14, 2.0) << std::endl; // OK: double是Numeric
std::cout << divide(10, 3) << std::endl; // OK: 自动推导
// 容器打印
std::vector<int> vec = {1, 2, 3, 4, 5};
print_container(vec); // OK: vector满足Printable和Container
// 基于概念的重载
process(42); // 调用integral版本
process(3.14); // 调用floating_point版本
process("hello"); // 调用其他类型版本
// 比较操作
std::cout << max_value(10, 20) << std::endl;
std::cout << max_value(3.14, 2.71) << std::endl;
// 编译错误示例(取消注释会导致编译错误)
// add("hello", "world"); // 错误:string不是Numeric
// multiply(vec, vec); // 错误:vector不是Numeric
return 0;
}
标准库提供的常用概念:
cpp
#include <concepts>
// 核心语言概念
std::same_as<T, U> // T和U是相同类型
std::derived_from<T, U> // T派生自U
std::convertible_to<T, U> // T可转换为U
std::common_reference_with<T, U> // T和U有公共引用类型
// 算术概念
std::integral<T> // T是整数类型
std::signed_integral<T> // T是有符号整数
std::unsigned_integral<T> // T是无符号整数
std::floating_point<T> // T是浮点类型
// 比较概念
std::equality_comparable<T> // T支持==比较
std::totally_ordered<T> // T支持<, >, ==等全序比较
// 对象概念
std::movable<T> // T可移动
std::copyable<T> // T可复制
std::destructible<T> // T可析构
std::constructible_from<T, Args...> // T可从Args构造
优点: 大幅改善模板错误信息、在编译期精确检查模板参数是否满足要求、支持基于概念的重载和特化、使泛型代码意图更明确。
协程 (Coroutines)
目标: 提供语言级别的支持,简化异步编程(如网络I/O、生成器)和惰性求值,避免回调地狱或复杂的状态机管理。
机制: 引入新的关键字 co_await
, co_yield
, co_return
。函数包含这些关键字即成为协程。编译器自动生成维持协程状态(帧)的代码。
核心类型: std::coroutine_handle
, std::coroutine_traits
, 以及相关的 promise 类型。
代码示例:
cpp
#include <coroutine>
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
// 1. 简单的生成器协程
template<typename T>
struct Generator {
struct promise_type {
T current_value;
Generator get_return_object() {
return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
std::suspend_always yield_value(T value) {
current_value = value;
return {};
}
void return_void() {}
void unhandled_exception() {}
};
std::coroutine_handle<promise_type> h;
explicit Generator(std::coroutine_handle<promise_type> handle) : h(handle) {}
~Generator() {
if (h) h.destroy();
}
// 移动构造和赋值
Generator(Generator&& other) noexcept : h(other.h) {
other.h = nullptr;
}
Generator& operator=(Generator&& other) noexcept {
if (this != &other) {
if (h) h.destroy();
h = other.h;
other.h = nullptr;
}
return *this;
}
// 迭代器接口
struct iterator {
std::coroutine_handle<promise_type> h;
iterator(std::coroutine_handle<promise_type> handle) : h(handle) {}
iterator& operator++() {
h.resume();
if (h.done()) h = nullptr;
return *this;
}
T operator*() const {
return h.promise().current_value;
}
bool operator!=(const iterator& other) const {
return h != other.h;
}
};
iterator begin() {
if (h) {
h.resume();
if (h.done()) return iterator{nullptr};
}
return iterator{h};
}
iterator end() {
return iterator{nullptr};
}
};
// 斐波那契数列生成器
Generator<int> fibonacci(int max_count) {
int a = 0, b = 1;
for (int i = 0; i < max_count; ++i) {
co_yield a;
auto temp = a + b;
a = b;
b = temp;
}
}
// 范围生成器
Generator<int> range(int start, int end, int step = 1) {
for (int i = start; i < end; i += step) {
co_yield i;
}
}
// 2. 简单的异步任务协程
struct Task {
struct promise_type {
Task get_return_object() {
return Task{std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
std::coroutine_handle<promise_type> h;
explicit Task(std::coroutine_handle<promise_type> handle) : h(handle) {}
~Task() {
if (h) h.destroy();
}
// 禁止复制,允许移动
Task(const Task&) = delete;
Task& operator=(const Task&) = delete;
Task(Task&& other) noexcept : h(other.h) {
other.h = nullptr;
}
Task& operator=(Task&& other) noexcept {
if (this != &other) {
if (h) h.destroy();
h = other.h;
other.h = nullptr;
}
return *this;
}
};
// 简单的等待器
struct Awaiter {
int delay_ms;
bool await_ready() { return delay_ms <= 0; }
void await_suspend(std::coroutine_handle<> handle) {
std::thread([handle, this]() {
std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
handle.resume();
}).detach();
}
void await_resume() {}
};
// 异步任务示例
Task async_task(const std::string& name, int delay) {
std::cout << name << " started" << std::endl;
co_await Awaiter{delay};
std::cout << name << " finished after " << delay << "ms" << std::endl;
}
int main() {
// 1. 生成器示例
std::cout << "=== 生成器示例 ===" << std::endl;
std::cout << "斐波那契数列前10项: ";
for (auto value : fibonacci(10)) {
std::cout << value << " ";
}
std::cout << std::endl;
std::cout << "范围[0, 10), 步长2: ";
for (auto value : range(0, 10, 2)) {
std::cout << value << " ";
}
std::cout << std::endl;
// 2. 异步任务示例
std::cout << "\n=== 异步任务示例 ===" << std::endl;
auto task1 = async_task("Task1", 1000);
auto task2 = async_task("Task2", 500);
auto task3 = async_task("Task3", 1500);
// 等待所有任务完成(简化示例)
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
return 0;
}
协程的三个关键字:
co_await
: 暂停协程执行,等待某个异步操作完成co_yield
: 暂停协程并返回一个值(用于生成器)co_return
: 结束协程执行并可选地返回一个值
协程的优势:
- 简化异步编程: 避免回调地狱,代码更直观
- 惰性求值: 生成器只在需要时计算下一个值
- 内存效率: 协程栈比线程栈小得多
- 可组合性: 协程可以轻松组合和链式调用
用途: 异步I/O、生成器、惰性序列、状态机等。
三向比较(飞船运算符)
目标: 简化用户自定义类型的比较运算符(==
, !=
, <
, <=
, >
, >=
)的定义。
机制: 定义一个 operator<=>
(俗称飞船运算符)。它返回一个比较类别类型(std::strong_ordering
, std::weak_ordering
, std::partial_ordering
),编译器可以根据这个运算符自动生成所有六个常规比较运算符(如果未显式定义它们)。
代码示例:
cpp
#include <compare>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
// 1. 基本的三向比较示例
struct Point {
int x, y;
// 自动生成所有比较运算符
auto operator<=>(const Point& other) const = default;
// 注意:C++20中,== 需要单独定义或使用 = default
bool operator==(const Point& other) const = default;
};
// 2. 自定义三向比较逻辑
struct Person {
std::string name;
int age;
// 先按年龄比较,年龄相同则按姓名比较
std::strong_ordering operator<=>(const Person& other) const {
if (auto cmp = age <=> other.age; cmp != 0) {
return cmp;
}
return name <=> other.name;
}
bool operator==(const Person& other) const {
return age == other.age && name == other.name;
}
};
// 3. 不同比较类别的示例
struct Version {
int major, minor, patch;
// 强序比较:完全可比较,相等具有传递性
std::strong_ordering operator<=>(const Version& other) const {
if (auto cmp = major <=> other.major; cmp != 0) return cmp;
if (auto cmp = minor <=> other.minor; cmp != 0) return cmp;
return patch <=> other.patch;
}
bool operator==(const Version& other) const = default;
};
// 4. 弱序比较示例
struct CaseInsensitiveString {
std::string value;
// 弱序:大小写不敏感比较
std::weak_ordering operator<=>(const CaseInsensitiveString& other) const {
auto to_lower = [](std::string s) {
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
return s;
};
return to_lower(value) <=> to_lower(other.value);
}
bool operator==(const CaseInsensitiveString& other) const {
return (*this <=> other) == 0;
}
};
// 5. 偏序比较示例(浮点数)
struct FloatWrapper {
double value;
// 偏序:考虑NaN的情况
std::partial_ordering operator<=>(const FloatWrapper& other) const {
return value <=> other.value;
}
bool operator==(const FloatWrapper& other) const {
return value == other.value;
}
};
// 6. 混合类型比较
struct Temperature {
double celsius;
explicit Temperature(double c) : celsius(c) {}
// 与double直接比较
std::partial_ordering operator<=>(double other_celsius) const {
return celsius <=> other_celsius;
}
bool operator==(double other_celsius) const {
return celsius == other_celsius;
}
// 温度之间的比较
auto operator<=>(const Temperature& other) const = default;
bool operator==(const Temperature& other) const = default;
};
// 7. 复杂对象的比较
struct Student {
std::string name;
double gpa;
int graduation_year;
// 按GPA降序,然后按毕业年份升序,最后按姓名升序
std::strong_ordering operator<=>(const Student& other) const {
// GPA降序(注意顺序颠倒)
if (auto cmp = other.gpa <=> gpa; cmp != 0) return cmp;
// 毕业年份升序
if (auto cmp = graduation_year <=> other.graduation_year; cmp != 0) return cmp;
// 姓名升序
return name <=> other.name;
}
bool operator==(const Student& other) const {
return name == other.name && gpa == other.gpa && graduation_year == other.graduation_year;
}
};
int main() {
// 1. 基本点比较
Point p1{1, 2};
Point p2{3, 4};
Point p3{1, 2};
std::cout << "=== Point 比较 ===" << std::endl;
std::cout << "p1 < p2: " << (p1 < p2) << std::endl;
std::cout << "p1 == p3: " << (p1 == p3) << std::endl;
std::cout << "p1 != p2: " << (p1 != p2) << std::endl;
// 2. 人员比较
Person alice{"Alice", 25};
Person bob{"Bob", 30};
Person charlie{"Charlie", 25};
std::cout << "\n=== Person 比较 ===" << std::endl;
std::cout << "alice < bob: " << (alice < bob) << std::endl;
std::cout << "alice < charlie: " << (alice < charlie) << std::endl;
// 3. 版本比较
Version v1{1, 2, 3};
Version v2{1, 2, 4};
Version v3{2, 0, 0};
std::cout << "\n=== Version 比较 ===" << std::endl;
std::cout << "v1 < v2: " << (v1 < v2) << std::endl;
std::cout << "v2 < v3: " << (v2 < v3) << std::endl;
// 4. 大小写不敏感字符串
CaseInsensitiveString s1{"Hello"};
CaseInsensitiveString s2{"HELLO"};
CaseInsensitiveString s3{"World"};
std::cout << "\n=== 大小写不敏感字符串 ===" << std::endl;
std::cout << "\"Hello\" == \"HELLO\": " << (s1 == s2) << std::endl;
std::cout << "\"Hello\" < \"World\": " << (s1 < s3) << std::endl;
// 5. 浮点数比较(包含NaN)
FloatWrapper f1{3.14};
FloatWrapper f2{2.71};
FloatWrapper f3{std::numeric_limits<double>::quiet_NaN()};
std::cout << "\n=== 浮点数比较 ===" << std::endl;
std::cout << "3.14 > 2.71: " << (f1 > f2) << std::endl;
std::cout << "NaN == NaN: " << (f3 == f3) << std::endl; // false
std::cout << "NaN < 3.14: " << (f3 < f1) << std::endl; // false
// 6. 温度比较
Temperature t1{25.0};
Temperature t2{30.0};
std::cout << "\n=== 温度比较 ===" << std::endl;
std::cout << "25°C < 30°C: " << (t1 < t2) << std::endl;
std::cout << "25°C == 25.0: " << (t1 == 25.0) << std::endl;
// 7. 学生排序
std::vector<Student> students = {
{"Alice", 3.8, 2024},
{"Bob", 3.9, 2023},
{"Charlie", 3.8, 2023},
{"David", 3.9, 2024}
};
std::sort(students.begin(), students.end());
std::cout << "\n=== 学生排序(按GPA降序,年份升序,姓名升序)===" << std::endl;
for (const auto& student : students) {
std::cout << student.name << " (GPA: " << student.gpa
<< ", 毕业年份: " << student.graduation_year << ")" << std::endl;
}
return 0;
}
比较类别说明:
-
std::strong_ordering
: 强序,所有值都可比较,相等具有传递性- 返回值:
less
,equal
,greater
- 适用于:整数、字符串等
- 返回值:
-
std::weak_ordering
: 弱序,允许等价但不相等的值- 返回值:
less
,equivalent
,greater
- 适用于:大小写不敏感字符串比较
- 返回值:
-
std::partial_ordering
: 偏序,某些值可能无法比较- 返回值:
less
,equivalent
,greater
,unordered
- 适用于:浮点数(包含NaN)
- 返回值:
优点: 减少样板代码,确保比较运算符行为一致,支持隐式生成。
指定初始化 (Designated Initializers)
机制: 允许在初始化聚合类型(如结构体)时,显式指定要初始化的成员名称,使用 {.member1 = value1, .member2 = value2}
语法(类似于C语言)。
规则: 初始化器必须按照成员声明的顺序出现(C++20要求严格顺序,C99允许乱序),不能嵌套使用,不能与常规初始化混合。注意:C++20不支持数组的指定初始化。
代码示例:
cpp
#include <iostream>
#include <string>
#include <vector>
// 1. 基本结构体的指定初始化
struct Point {
int x;
int y;
int z;
};
// 2. 包含不同类型成员的结构体
struct Person {
std::string name;
int age;
double height;
bool is_student;
};
// 3. 嵌套结构体
struct Address {
std::string street;
std::string city;
int zip_code;
};
struct Employee {
std::string name;
int id;
Address address;
double salary;
};
// 4. 包含数组成员的结构体
struct Config {
std::string app_name;
int version[3]; // major, minor, patch
bool debug_mode;
double timeout;
};
// 5. 模板结构体
template<typename T>
struct Container {
T value;
std::string description;
bool is_valid;
};
int main() {
// 1. 基本指定初始化
std::cout << "=== 基本指定初始化 ===" << std::endl;
Point p1 = {.x = 10, .y = 20, .z = 30};
Point p2 = {.x = 5, .y = 15}; // z 默认初始化为 0
Point p3 = {.x = 1}; // y, z 默认初始化为 0
std::cout << "p1: (" << p1.x << ", " << p1.y << ", " << p1.z << ")" << std::endl;
std::cout << "p2: (" << p2.x << ", " << p2.y << ", " << p2.z << ")" << std::endl;
std::cout << "p3: (" << p3.x << ", " << p3.y << ", " << p3.z << ")" << std::endl;
// 2. 复杂类型的指定初始化
std::cout << "\n=== 复杂类型指定初始化 ===" << std::endl;
Person alice = {
.name = "Alice Johnson",
.age = 25,
.height = 165.5,
.is_student = true
};
Person bob = {
.name = "Bob Smith",
.age = 30
// height 和 is_student 使用默认值
};
std::cout << alice.name << ": " << alice.age << " years, "
<< alice.height << "cm, student: " << alice.is_student << std::endl;
std::cout << bob.name << ": " << bob.age << " years, "
<< bob.height << "cm, student: " << bob.is_student << std::endl;
// 3. 嵌套结构体(注意:C++20不支持嵌套指定初始化)
std::cout << "\n=== 嵌套结构体 ===" << std::endl;
Employee emp1 = {
.name = "John Doe",
.id = 12345,
.address = {"123 Main St", "New York", 10001}, // 常规初始化
.salary = 75000.0
};
std::cout << emp1.name << " (ID: " << emp1.id << ")" << std::endl;
std::cout << "Address: " << emp1.address.street << ", "
<< emp1.address.city << " " << emp1.address.zip_code << std::endl;
std::cout << "Salary: $" << emp1.salary << std::endl;
// 4. 包含数组的结构体
std::cout << "\n=== 包含数组的结构体 ===" << std::endl;
Config app_config = {
.app_name = "MyApp",
.version = {2, 1, 0}, // 数组使用常规初始化
.debug_mode = true,
.timeout = 30.0
};
std::cout << "App: " << app_config.app_name << std::endl;
std::cout << "Version: " << app_config.version[0] << "."
<< app_config.version[1] << "." << app_config.version[2] << std::endl;
std::cout << "Debug: " << app_config.debug_mode << ", Timeout: "
<< app_config.timeout << "s" << std::endl;
// 5. 模板结构体的指定初始化
std::cout << "\n=== 模板结构体 ===" << std::endl;
Container<int> int_container = {
.value = 42,
.description = "Integer container",
.is_valid = true
};
Container<std::string> str_container = {
.value = "Hello, World!",
.description = "String container"
// is_valid 默认初始化为 false
};
std::cout << "Int container: " << int_container.value
<< " (" << int_container.description << ")" << std::endl;
std::cout << "String container: " << str_container.value
<< " (" << str_container.description << ")" << std::endl;
// 6. 部分初始化示例
std::cout << "\n=== 部分初始化 ===" << std::endl;
// 只初始化前几个成员
Person partial_person = {
.name = "Charlie Brown"
// 其他成员使用默认值
};
std::cout << "Partial person: " << partial_person.name
<< ", age: " << partial_person.age << std::endl;
// 编译错误示例(取消注释会导致编译错误)
/*
// 错误:顺序不对
Point wrong_order = {.y = 10, .x = 20};
// 错误:混合指定初始化和常规初始化
Point mixed = {10, .y = 20};
// 错误:嵌套指定初始化
Employee nested_designated = {
.name = "Jane",
.address = {.street = "456 Oak St"} // 不支持
};
*/
return 0;
}
使用规则和限制:
- 顺序要求: 指定初始化器必须按照成员声明的顺序出现
- 不能混合: 不能在同一个初始化列表中混合指定初始化和常规初始化
- 不支持嵌套: 不能对嵌套的聚合类型使用指定初始化
- 不支持数组: C++20不支持数组的指定初始化(与C99不同)
- 只能用于聚合类型: 只能用于聚合类型(没有用户定义构造函数的类/结构体)
优点: 提高初始化代码的可读性和安全性,避免因成员顺序错误导致的初始化错误。
范围 for 循环中的初始化语句
机制: 允许在基于范围的 for
循环中初始化一个变量,语法为 for (init-statement; for-range-declaration : for-range-init)
。
代码示例:
cpp
#include <iostream>
#include <vector>
#include <string>
#include <map>
int main() {
std::vector<std::string> words = {"hello", "world", "C++", "twenty"};
std::map<std::string, int> word_count;
// 1. 基本用法:在循环中声明计数器
std::cout << "=== 带索引的范围循环 ===" << std::endl;
for (int i = 0; const auto& word : words) {
std::cout << "Index " << i << ": " << word << std::endl;
++i;
}
// 2. 初始化多个变量
std::cout << "\n=== 初始化多个变量 ===" << std::endl;
for (int count = 0, sum = 0; const auto& word : words) {
sum += word.length();
++count;
std::cout << "Word " << count << ": " << word
<< " (累计长度: " << sum << ")" << std::endl;
}
// 3. 使用初始化语句设置容器
std::cout << "\n=== 使用初始化语句设置容器 ===" << std::endl;
for (auto container = std::vector<int>{1, 2, 3, 4, 5}; const auto& value : container) {
std::cout << value * value << " ";
}
std::cout << std::endl;
// 4. 实际应用:统计和处理
std::cout << "\n=== 统计处理示例 ===" << std::endl;
for (size_t processed = 0; const auto& word : words) {
word_count[word] = word.length();
++processed;
std::cout << "已处理 " << processed << " 个单词" << std::endl;
}
// 5. 与传统for循环的对比
std::cout << "\n=== 传统方式 vs 新方式 ===" << std::endl;
// 传统方式(污染外层作用域)
int traditional_index = 0;
for (const auto& word : words) {
if (traditional_index == 2) break;
std::cout << "传统方式 - Index " << traditional_index << ": " << word << std::endl;
++traditional_index;
}
// traditional_index 仍然存在于外层作用域
// 新方式(作用域限制在循环内)
for (int modern_index = 0; const auto& word : words) {
if (modern_index == 2) break;
std::cout << "现代方式 - Index " << modern_index << ": " << word << std::endl;
++modern_index;
}
// modern_index 在这里不可访问
return 0;
}
优点: 方便在循环作用域内声明循环计数器或其他临时变量,避免污染外层作用域。
[[likely]] 和 [[unlikely]] 属性
目标: 向编译器提供分支预测的提示,优化代码执行路径。
用法: 应用于 if
, switch
, 循环语句的标签或条件之前。
代码示例:
cpp
#include <iostream>
#include <vector>
#include <random>
#include <chrono>
// 模拟一个可能很少失败的操作
bool risky_operation(int value) {
return value % 100 != 0; // 99% 的情况返回 true
}
// 处理数据的函数
void process_data(const std::vector<int>& data) {
int success_count = 0;
int failure_count = 0;
for (const auto& value : data) {
// 提示编译器这个分支很可能被执行
if (risky_operation(value)) [[likely]] {
success_count++;
// 大部分情况下执行的代码
} else [[unlikely]] {
failure_count++;
// 很少执行的错误处理代码
std::cout << "处理失败: " << value << std::endl;
}
}
std::cout << "成功: " << success_count << ", 失败: " << failure_count << std::endl;
}
// switch 语句中的使用
void handle_request(int request_type) {
switch (request_type) {
[[likely]] case 1: // 最常见的请求类型
std::cout << "处理常见请求" << std::endl;
break;
case 2:
std::cout << "处理普通请求" << std::endl;
break;
[[unlikely]] case 99: // 很少见的请求类型
std::cout << "处理特殊请求" << std::endl;
break;
[[unlikely]] default: // 错误情况
std::cout << "未知请求类型" << std::endl;
break;
}
}
// 循环中的使用
void search_in_sorted_array(const std::vector<int>& sorted_data, int target) {
for (const auto& value : sorted_data) {
if (value == target) [[unlikely]] {
// 找到目标的概率较低
std::cout << "找到目标值: " << target << std::endl;
return;
}
if (value > target) [[likely]] {
// 在排序数组中,这种情况更可能发生
std::cout << "目标值不存在" << std::endl;
return;
}
}
}
// 性能关键代码示例
class Cache {
private:
std::vector<std::pair<int, std::string>> cache_data;
public:
std::string get(int key) {
for (const auto& [k, v] : cache_data) {
if (k == key) [[likely]] {
// 缓存命中是期望的常见情况
return v;
}
}
// 缓存未命中,需要从其他地方加载
[[unlikely]] {
std::cout << "缓存未命中,加载数据..." << std::endl;
return "default_value";
}
}
};
int main() {
// 1. 基本的 likely/unlikely 使用
std::cout << "=== 基本 likely/unlikely 示例 ===" << std::endl;
std::vector<int> test_data;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, 1000);
// 生成测试数据
for (int i = 0; i < 10000; ++i) {
test_data.push_back(dis(gen));
}
auto start = std::chrono::high_resolution_clock::now();
process_data(test_data);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "处理时间: " << duration.count() << " 微秒" << std::endl;
// 2. switch 语句示例
std::cout << "\n=== Switch 语句示例 ===" << std::endl;
std::vector<int> request_types = {1, 1, 1, 2, 1, 99, 1, 1, 2, 1};
for (int type : request_types) {
handle_request(type);
}
// 3. 搜索示例
std::cout << "\n=== 搜索示例 ===" << std::endl;
std::vector<int> sorted_array = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
search_in_sorted_array(sorted_array, 7);
search_in_sorted_array(sorted_array, 8);
// 4. 缓存示例
std::cout << "\n=== 缓存示例 ===" << std::endl;
Cache cache;
std::cout << cache.get(1) << std::endl;
std::cout << cache.get(2) << std::endl;
return 0;
}
重要说明:
- 只是提示: 这些属性只是给编译器的提示,编译器可以选择忽略
- 性能优化: 主要用于性能关键的代码路径
- 分支预测: 帮助CPU的分支预测器做出更好的预测
- 不要滥用: 只在确实了解代码执行模式时使用
注意: 只是提示,编译器可以选择忽略。对性能关键代码有用。
constexpr 增强
C++20 大幅扩展了 constexpr
的能力,包括虚函数、动态转换、异常处理、动态内存分配等。
代码示例:
cpp
#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <typeinfo>
// 1. constexpr 虚函数
struct Base {
constexpr virtual ~Base() = default;
constexpr virtual int getValue() const = 0;
constexpr virtual const char* getType() const = 0;
};
struct Derived1 : public Base {
int value;
constexpr Derived1(int v) : value(v) {}
constexpr int getValue() const override {
return value;
}
constexpr const char* getType() const override {
return "Derived1";
}
};
struct Derived2 : public Base {
int multiplier;
constexpr Derived2(int m) : multiplier(m) {}
constexpr int getValue() const override {
return multiplier * 10;
}
constexpr const char* getType() const override {
return "Derived2";
}
};
// 使用 constexpr 虚函数
constexpr int processBase(const Base& base) {
return base.getValue() * 2;
}
// 2. constexpr dynamic_cast
constexpr int safeCast(const Base& base) {
if (const auto* d1 = dynamic_cast<const Derived1*>(&base)) {
return d1->value + 100;
} else if (const auto* d2 = dynamic_cast<const Derived2*>(&base)) {
return d2->multiplier + 200;
}
return -1;
}
// 3. constexpr try-catch(主要用于SFINAE和模板元编程)
template<typename T>
constexpr bool canAdd(const T& a, const T& b) {
try {
auto result = a + b;
return true;
} catch (...) {
return false; // 在编译期,这实际上不会被执行
}
}
// 4. constexpr std::vector 和 std::string
constexpr std::vector<int> createVector() {
std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
return vec;
}
constexpr std::string createString() {
std::string str = "Hello";
str += ", ";
str += "World!";
return str;
}
constexpr int sumVector() {
auto vec = createVector();
int sum = 0;
for (const auto& value : vec) {
sum += value;
}
return sum;
}
// 5. consteval 立即函数
consteval int square(int n) {
return n * n;
}
consteval int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
// consteval 函数必须在编译时求值
consteval const char* getCompileTimeString() {
return "This is computed at compile time";
}
// 6. constinit 静态初始化
constinit static int global_value = 42; // 保证静态初始化
constinit static std::string global_string = "initialized"; // 编译错误:string没有constexpr构造函数
// 正确的 constinit 用法
constinit static int computed_value = square(10); // OK: square是consteval
// 7. 复杂的编译期计算
constexpr std::vector<int> generatePrimes(int max_num) {
std::vector<int> primes;
for (int num = 2; num <= max_num; ++num) {
bool is_prime = true;
for (int i = 2; i * i <= num; ++i) {
if (num % i == 0) {
is_prime = false;
break;
}
}
if (is_prime) {
primes.push_back(num);
}
}
return primes;
}
constexpr int countPrimesUpTo(int n) {
auto primes = generatePrimes(n);
return primes.size();
}
// 8. constexpr 算法
constexpr std::vector<int> sortVector(std::vector<int> vec) {
// 简单的冒泡排序(在编译期执行)
for (size_t i = 0; i < vec.size(); ++i) {
for (size_t j = 0; j < vec.size() - 1 - i; ++j) {
if (vec[j] > vec[j + 1]) {
auto temp = vec[j];
vec[j] = vec[j + 1];
vec[j + 1] = temp;
}
}
}
return vec;
}
int main() {
// 1. constexpr 虚函数测试
std::cout << "=== constexpr 虚函数 ===" << std::endl;
constexpr Derived1 d1(42);
constexpr Derived2 d2(5);
constexpr int result1 = processBase(d1); // 编译期计算
constexpr int result2 = processBase(d2); // 编译期计算
std::cout << "Derived1 处理结果: " << result1 << std::endl;
std::cout << "Derived2 处理结果: " << result2 << std::endl;
// 2. constexpr dynamic_cast
std::cout << "\n=== constexpr dynamic_cast ===" << std::endl;
constexpr int cast_result1 = safeCast(d1);
constexpr int cast_result2 = safeCast(d2);
std::cout << "Derived1 转换结果: " << cast_result1 << std::endl;
std::cout << "Derived2 转换结果: " << cast_result2 << std::endl;
// 3. constexpr 容器
std::cout << "\n=== constexpr 容器 ===" << std::endl;
constexpr auto compile_time_vector = createVector();
constexpr auto compile_time_string = createString();
constexpr int vector_sum = sumVector();
std::cout << "编译期字符串: " << compile_time_string.c_str() << std::endl;
std::cout << "编译期向量和: " << vector_sum << std::endl;
// 4. consteval 函数
std::cout << "\n=== consteval 函数 ===" << std::endl;
constexpr int sq_5 = square(5); // 编译期计算
constexpr int fact_6 = factorial(6); // 编译期计算
std::cout << "5的平方: " << sq_5 << std::endl;
std::cout << "6的阶乘: " << fact_6 << std::endl;
std::cout << "编译期字符串: " << getCompileTimeString() << std::endl;
// 5. 复杂编译期计算
std::cout << "\n=== 复杂编译期计算 ===" << std::endl;
constexpr int prime_count = countPrimesUpTo(100);
constexpr auto primes = generatePrimes(30);
std::cout << "100以内的质数个数: " << prime_count << std::endl;
std::cout << "30以内的质数: ";
for (const auto& prime : primes) {
std::cout << prime << " ";
}
std::cout << std::endl;
// 6. constexpr 排序
std::cout << "\n=== constexpr 排序 ===" << std::endl;
constexpr auto unsorted = std::vector<int>{5, 2, 8, 1, 9, 3};
constexpr auto sorted = sortVector(unsorted);
std::cout << "排序后: ";
for (const auto& value : sorted) {
std::cout << value << " ";
}
std::cout << std::endl;
// 7. constinit 变量
std::cout << "\n=== constinit 变量 ===" << std::endl;
std::cout << "全局值: " << global_value << std::endl;
std::cout << "计算值: " << computed_value << std::endl;
// 编译错误示例(取消注释会导致编译错误)
/*
int runtime_value = 10;
consteval int runtime_square = square(runtime_value); // 错误:runtime_value不是编译期常量
*/
return 0;
}
新增关键字说明:
-
consteval
: 立即函数,强制在编译时求值cppconsteval int compile_time_only(int x) { return x * x; }
-
constinit
: 确保静态/线程局部变量的静态初始化cppconstinit static int value = 42; // 保证静态初始化
主要增强:
- 虚函数 :
virtual
函数现在可以在constexpr
上下文中使用 dynamic_cast
/typeid
: 允许在常量表达式中使用动态转换try-catch
: 允许在constexpr
函数中使用异常处理- 标准库容器 :
std::vector
、std::string
等支持constexpr
- 动态内存分配: 在编译期可以进行受限的动态内存分配
using enum 声明
机制: 将枚举类型的所有枚举项引入当前作用域,简化枚举的使用。
代码示例:
cpp
#include <iostream>
enum class Color { Red, Green, Blue };
enum class Status { Active, Inactive, Pending };
void processColor() {
using enum Color; // 引入所有Color枚举项
Color c1 = Red; // 无需 Color::Red
Color c2 = Green;
Color c3 = Blue;
std::cout << "Colors: " << static_cast<int>(c1) << ", "
<< static_cast<int>(c2) << ", " << static_cast<int>(c3) << std::endl;
}
void processStatus() {
using Status::Active; // 只引入单个枚举项
Status s1 = Active; // OK
Status s2 = Status::Pending; // 仍需前缀
}
int main() {
processColor();
processStatus();
return 0;
}
其他语言特性
聚合体的圆括号初始化:
cpp
struct Base { int x; };
struct Derived : Base { int y; };
Derived d1{Base{1}, 2}; // C++17: 花括号
Derived d2(Base{1}, 2); // C++20: 圆括号
位域默认初始化:
cpp
struct Flags {
unsigned int flag1 : 1 = 1; // 默认为1
unsigned int flag2 : 2 = 0; // 默认为0
unsigned int flag3 : 3; // 无默认值
};
VA_OPT 宏:
cpp
#define LOG(msg, ...) printf(msg __VA_OPT__(,) __VA_ARGS__)
LOG("Hello"); // printf("Hello")
LOG("Value: %d", 42); // printf("Value: %d", 42)
Lambda 捕获增强:
cpp
class MyClass {
public:
void method() {
int x = 10;
// C++20 明确允许
auto lambda1 = [=, this]() { return x + member_var; };
// 推荐的明确写法
auto lambda2 = [this, x]() { return x + member_var; };
}
private:
int member_var = 5;
};
📚 二、标准库特性
1. 范围库 (Ranges Library)
目标: 提供操作元素序列的现代化、可组合、惰性求值的算法和视图。
代码示例:
cpp
#include <ranges>
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 链式操作:过滤偶数 -> 平方 -> 取前3个
auto result = numbers
| std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return n * n; })
| std::views::take(3);
std::cout << "偶数平方前3个: ";
for (int value : result) {
std::cout << value << " "; // 输出: 4 16 36
}
std::cout << std::endl;
// 生成无限序列
auto infinite_odds = std::views::iota(1)
| std::views::filter([](int n) { return n % 2 == 1; })
| std::views::take(5);
std::cout << "前5个奇数: ";
for (int value : infinite_odds) {
std::cout << value << " "; // 输出: 1 3 5 7 9
}
std::cout << std::endl;
// 范围算法
std::vector<std::string> words = {"hello", "world", "cpp", "ranges"};
std::ranges::sort(words); // 直接对范围排序
auto it = std::ranges::find(words, "cpp");
if (it != words.end()) {
std::cout << "找到单词: " << *it << std::endl;
}
// 复杂的范围操作
std::vector<std::vector<int>> matrix = {{1, 2}, {3, 4}, {5, 6}};
auto flattened = matrix | std::views::join;
std::cout << "展平矩阵: ";
for (int value : flattened) {
std::cout << value << " "; // 输出: 1 2 3 4 5 6
}
std::cout << std::endl;
return 0;
}
核心组件:
- 范围概念:
std::ranges::range
,std::ranges::view
,std::ranges::sized_range
- 视图 (Views):
filter
,transform
,take
,join
,iota
等 - 范围算法:
std::ranges::sort
,std::ranges::find
,std::ranges::for_each
优点: 代码简洁、惰性求值、可组合性强、支持无限序列
2. std::format 格式化库
目标: 提供现代化、类型安全、高性能的文本格式化机制。
代码示例:
cpp
#include <format>
#include <iostream>
#include <string>
#include <vector>
struct Point {
double x, y;
};
// 为自定义类型提供格式化支持
template<>
struct std::formatter<Point> {
constexpr auto parse(format_parse_context& ctx) {
return ctx.begin();
}
template<typename FormatContext>
auto format(const Point& p, FormatContext& ctx) {
return std::format_to(ctx.out(), "({:.2f}, {:.2f})", p.x, p.y);
}
};
int main() {
// 基本格式化
std::string name = "Alice";
int age = 30;
double salary = 75000.50;
std::string basic = std::format("姓名: {}, 年龄: {}, 薪水: {:.2f}", name, age, salary);
std::cout << basic << std::endl;
// 位置参数
std::string positioned = std::format("{1} 今年 {0} 岁", age, name);
std::cout << positioned << std::endl;
// 格式说明符
int number = 42;
std::cout << std::format("十进制: {}, 十六进制: {:x}, 八进制: {:o}, 二进制: {:b}\n",
number, number, number, number);
// 对齐和宽度
std::cout << std::format("左对齐: '{:<10}', 右对齐: '{:>10}', 居中: '{:^10}'\n",
"hello", "hello", "hello");
// 浮点数精度
double pi = 3.14159265359;
std::cout << std::format("π = {:.2f}, π = {:.6f}, π = {:e}\n", pi, pi, pi);
// 自定义类型
Point p{3.14, 2.71};
std::cout << std::format("点坐标: {}\n", p);
// 容器格式化(需要自定义formatter或使用范围)
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::string result = "数字: ";
for (size_t i = 0; i < numbers.size(); ++i) {
result += std::format("{}{}", numbers[i], (i < numbers.size() - 1) ? ", " : "");
}
std::cout << result << std::endl;
// 性能优化:预计算大小
auto size = std::formatted_size("Hello {}", "World");
std::cout << std::format("格式化字符串大小: {} 字节\n", size);
// 直接输出到迭代器
std::string buffer;
buffer.reserve(100);
std::format_to(std::back_inserter(buffer), "直接输出: {} + {} = {}", 10, 20, 30);
std::cout << buffer << std::endl;
return 0;
}
主要特性:
- 类型安全: 编译时检查参数类型
- 丰富格式: 支持对齐、宽度、精度、进制等
- 可扩展: 支持自定义类型的格式化
- 高性能: 通常优于
printf
和iostreams
- 相关函数:
std::formatted_size
,std::format_to
3. std::span
目标: 提供对连续内存序列的非占有视图,安全地传递数组或容器的一部分。
代码示例:
cpp
#include <span>
#include <vector>
#include <array>
#include <iostream>
// 函数接受span参数,可以处理各种容器类型
void print_elements(std::span<const int> data) {
std::cout << "元素个数: " << data.size() << ", 内容: ";
for (const auto& elem : data) {
std::cout << elem << " ";
}
std::cout << std::endl;
}
void modify_elements(std::span<int> data) {
for (auto& elem : data) {
elem *= 2; // 将每个元素乘以2
}
}
int main() {
// 不同类型的容器
std::vector<int> vec = {1, 2, 3, 4, 5};
std::array<int, 4> arr = {10, 20, 30, 40};
int c_array[] = {100, 200, 300};
// span可以从各种容器创建
std::span<int> span_vec(vec);
std::span<int> span_arr(arr);
std::span<int> span_c_array(c_array);
std::cout << "原始数据:\n";
print_elements(span_vec);
print_elements(span_arr);
print_elements(span_c_array);
// 修改数据
modify_elements(span_vec);
modify_elements(span_arr.subspan(1, 2)); // 只修改部分元素
std::cout << "\n修改后:\n";
print_elements(span_vec);
print_elements(span_arr);
// 子视图操作
std::span<int> sub_span = span_vec.subspan(1, 3); // 从索引1开始,取3个元素
std::cout << "\n子视图: ";
print_elements(sub_span);
// 固定大小的span
std::span<int, 3> fixed_span = span_c_array; // 编译时大小检查
std::cout << "固定大小span: ";
print_elements(fixed_span);
// span的其他操作
std::cout << "\nspan操作演示:\n";
std::cout << "第一个元素: " << span_vec.front() << std::endl;
std::cout << "最后一个元素: " << span_vec.back() << std::endl;
std::cout << "数据指针: " << span_vec.data() << std::endl;
std::cout << "是否为空: " << span_vec.empty() << std::endl;
return 0;
}
主要特性:
- 轻量级: 通常只包含指针和大小
- 类型安全: 编译时类型检查
- 统一接口: 可以处理数组、vector、array等
- 子视图: 支持
subspan()
操作
4. std::jthread (协作式中断线程)
目标: 提供比 std::thread
更安全、支持协作式中断的线程类型。
代码示例:
cpp
#include <thread>
#include <iostream>
#include <chrono>
#include <stop_token>
void worker_function(std::stop_token stoken, int id) {
int count = 0;
while (!stoken.stop_requested()) {
std::cout << "线程 " << id << " 工作中... (" << ++count << ")" << std::endl;
// 模拟工作,同时检查停止请求
if (std::this_thread::sleep_for(std::chrono::milliseconds(500));
stoken.stop_requested()) {
std::cout << "线程 " << id << " 收到停止请求" << std::endl;
break;
}
}
std::cout << "线程 " << id << " 结束" << std::endl;
}
void callback_example(std::stop_token stoken) {
// 注册停止回调
std::stop_callback callback(stoken, []() {
std::cout << "停止回调被触发!" << std::endl;
});
int count = 0;
while (!stoken.stop_requested() && count < 10) {
std::cout << "回调示例线程运行: " << ++count << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
}
int main() {
std::cout << "=== std::jthread 示例 ===\n";
// 创建jthread,自动管理生命周期
std::jthread worker1(worker_function, 1);
std::jthread worker2(worker_function, 2);
std::jthread callback_thread(callback_example);
// 让线程运行一段时间
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "\n请求停止所有线程...\n";
// 请求停止
worker1.request_stop();
worker2.request_stop();
callback_thread.request_stop();
// jthread析构时会自动join,无需手动调用
std::cout << "等待线程结束...\n";
// 也可以手动join
if (worker1.joinable()) worker1.join();
if (worker2.joinable()) worker2.join();
if (callback_thread.joinable()) callback_thread.join();
std::cout << "所有线程已结束\n";
// 演示stop_source和stop_token的独立使用
std::cout << "\n=== 独立使用 stop_token ===\n";
std::stop_source source;
std::stop_token token = source.get_token();
std::jthread independent_thread([token](std::stop_token) {
while (!token.stop_requested()) {
std::cout << "独立线程运行中..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(400));
}
std::cout << "独立线程结束" << std::endl;
});
std::this_thread::sleep_for(std::chrono::seconds(1));
source.request_stop(); // 通过source请求停止
return 0;
}
主要优势:
- 自动join: 析构时自动调用
join()
- 协作式中断: 通过
std::stop_token
安全停止 - RAII管理: 更安全的资源管理
- 向后兼容: 可以像
std::thread
一样使用
-
std::stop_token
/std::stop_source
/std::stop_callback
:- 目标: 为
std::jthread
提供协作式中断机制,也可独立使用。 - 机制:
std::stop_source
: 产生中断请求 (request_stop()
),拥有一个共享的停止状态。std::stop_token
: 从stop_source
获取,用于查询是否发生了中断请求 (stop_requested()
) 或注册回调。std::stop_callback
: 向stop_token
注册一个回调函数,在中断请求发生时(或如果已发生则立即)调用该回调。
- 优点: 标准化的、灵活的线程协作取消机制。
- 目标: 为
-
原子智能指针 (
std::atomic<
,std::atomic>
):- 目标: 提供对
std::shared_ptr
和std::weak_ptr
的原子操作支持。 - 机制: 类模板
std::atomic
和std::atomic
。提供load
,store
,exchange
,compare_exchange_weak/strong
等原子操作,以及std::atomic_is_lock_free
检查。 - 优点: 无需手动加锁即可在多线程环境中安全地读写
shared_ptr
/weak_ptr
本身(注意:不保护其指向的对象)。
- 目标: 提供对
-
std::latch
和std::barrier
:- 目标: 提供线程同步原语,协调多个线程在某个点上的汇合。
std::latch
: 一次性屏障。初始化一个计数值,线程调用count_down()
减少计数或wait()
阻塞直到计数减到零。计数到零后,所有等待的线程解除阻塞,后续的count_down
无操作,wait
立即返回。std::barrier
: 可重复使用的屏障。初始化一个计数值和一个(可选的)完成阶段函数。线程调用arrive_and_wait()
减少计数并阻塞,直到所有线程都到达。当计数减到零时,调用完成函数,然后重置计数并解除所有等待线程的阻塞,进入下一阶段。- 优点: 简化常见的多线程同步模式(如等待所有工作线程完成初始化、分阶段处理)。
-
std::counting_semaphore
/std::binary_semaphore
:- 目标: 提供计数信号量(资源计数器)和二元信号量(互斥锁)。
- 机制:
std::counting_semaphore<Max>
(其中Max
是最大计数值) 和std::binary_semaphore
(是std::counting_semaphore<1>
的别名)。核心操作:acquire()
(P 操作,获取资源,可能阻塞),try_acquire()
(非阻塞尝试),try_acquire_for()
/try_acquire_until()
(带超时尝试),release()
(V 操作,释放资源)。 - 优点: 标准化的信号量实现,用于控制对共享资源的并发访问数量。
-
std::source_location
:- 目标: 在代码中获取当前的源文件位置(文件名、行号、函数名、列号),替代
__FILE__
,__LINE__
等宏,且可作为函数默认参数。 - 机制: 类
std::source_location
。使用std::source_location::current()
静态方法获取调用点的位置信息。成员函数:file_name()
,line()
,column()
,function_name()
。 - 优点: 类型安全、可作为默认参数(宏不行)、更符合现代C++风格。
- 目标: 在代码中获取当前的源文件位置(文件名、行号、函数名、列号),替代
-
std::chrono
日历和时区扩展:- 目标: 提供完整的日历日期和时区处理能力。
- 机制:
- 日历类型:
std::chrono::year
,month
,day
,weekday
,month_day
,year_month
,year_month_day
,year_month_weekday
等。支持丰富的算术和比较操作。 - 时区支持:
std::chrono::time_zone
,std::chrono::zoned_time
(表示特定时区的绝对时间点),std::chrono::tzdb
(管理时区数据库)。支持在时区之间转换时间点、获取本地时间、处理夏令时等。 - 格式化和解析: 与
std::format
/std::parse
集成。
- 日历类型:
- 优点: 标准化的、强大的日期时间处理库,替代第三方库。
-
constexpr
算法和容器:- 机制: 许多标准算法(如
std::find
,std::sort
- 在满足constexpr
要求时)和容器(std::vector
,std::string
,std::array
,std::pair
,std::tuple
等)在 C++20 中被声明为可在constexpr
上下文中使用(通常要求元素类型是字面类型,操作在编译期可求值)。 - 优点: 支持在编译期进行更复杂的计算和数据结构操作。
- 机制: 许多标准算法(如
-
std::erase
/std::erase_if
(非成员函数):- 机制: 为序列容器 (
vector
,deque
,list
,forward_list
) 和关联容器 (map
,set
,unordered_map
,unordered_set
) 提供统一的非成员函数,用于删除满足特定条件或等于特定值的所有元素。 - 优点: 提供更一致、更简洁的擦除语法(相比容器的
erase
成员函数迭代器循环)。
- 机制: 为序列容器 (
-
std::bit_cast
:- 目标: 安全、低开销地重新解释一种对象类型为另一种具有相同大小的对象类型(类似
reinterpret_cast
,但保证constexpr
且避免未定义行为)。 - 机制:
template To bit_cast(const From& from) noexcept;
。要求sizeof(To) == sizeof(From)
且两者都是TriviallyCopyable
类型。 - 优点: 安全地进行位级别的类型转换(如浮点数到整数表示),避免
memcpy
或reinterpret_cast
的陷阱。
- 目标: 安全、低开销地重新解释一种对象类型为另一种具有相同大小的对象类型(类似
🚀 总结
C++20 是一次巨大的飞跃,引入了改变游戏规则的核心特性(模块、概念、协程 )以及大量提升开发效率和代码质量的库特性(范围、format、span、jthread、同步原语、日历时区)。它显著改善了泛型编程(概念)、编译构建(模块)、异步编程(协程)、并发编程(jthread, 信号量, latch/barrier)、文本处理(format)和日期时间处理(chrono扩展)等方面的体验。掌握 C++20 是编写现代、高效、安全 C++ 代码的关键。后续版本(C++23, C++26)在 C++20 的基础上继续完善和扩展这些特性。