C++20 新特性全面总结

C++20 新特性全面总结


核心思想:C++20 是继 C++11 之后最大的一次语言变革,被称为"C++的第二次革命"。它引入了四大旗舰特性------Concepts(概念)Ranges(范围)Coroutines(协程)Modules(模块) ,同时在语言和标准库层面带来了三路比较运算符、constexpr 的全面扩展、std::formatstd::span、日历/时区、协作式线程取消等大量现代化基础设施,标志着 C++ 正式进入"声明式、安全、高表达力"的新时代。


🚀 1. Concepts(概念)------ 约束模板参数

1.1 问题与动机

C++ 复制代码
/*
 *  C++17 模板错误信息的痛苦:
 *  ┌────────────────────────────────────────────────────────────┐
 *  │ template <typename T>                                      │
 *  │ void sort(T& container);                                   │
 *  │                                                            │
 *  │ sort(42);  // 编译错误 → 几十行不可读的错误信息              │
 *  │ "no matching function for call to 'sort'..."               │
 *  │ "...in instantiation of template..."                       │
 *  │ "...std::__1::__wrap_iter<int*>..."   (天书)               │
 *  └────────────────────────────────────────────────────────────┘
 *
 *  C++20 Concepts 的目标:
 *  ┌────────────────────────────────────────────────────────────┐
 *  │ 1. 让模板参数的约束显式化、可读化                           │
 *  │ 2. 提供清晰的编译错误信息                                   │
 *  │ 3. 替代 SFINAE / enable_if 的复杂手段                      │
 *  │ 4. 支持基于约束的重载决议                                   │
 *  └────────────────────────────────────────────────────────────┘
 */

1.2 定义与使用 Concept

C++ 复制代码
#include <concepts>
#include <type_traits>

// ═══ 定义 concept ═══
template <typename T>
concept Numeric = std::is_arithmetic_v<T>;

template <typename T>
concept Addable = requires(T a, T b) {
    { a + b } -> std::convertible_to<T>;   // a+b 的结果可转为 T
};

template <typename T>
concept Printable = requires(std::ostream& os, T val) {
    { os << val } -> std::same_as<std::ostream&>;
};

template <typename T>
concept Hashable = requires(T a) {
    { std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};

// 组合 concept
template <typename T>
concept PrintableNumeric = Numeric<T> && Printable<T>;

// ═══ 使用 concept 的四种语法 ═══

// 语法1:requires 子句
template <typename T>
    requires Numeric<T>
T add(T a, T b) { return a + b; }

// 语法2:尾置 requires
template <typename T>
T multiply(T a, T b) requires Numeric<T> { return a * b; }

// 语法3:受约束的模板参数(最推荐)
template <Numeric T>
T divide(T a, T b) { return a / b; }

// 语法4:简写函数模板(最简洁)
auto square(Numeric auto x) { return x * x; }

void concept_usage() {
    add(1, 2);          // ✅ int 满足 Numeric
    add(1.5, 2.5);      // ✅ double 满足 Numeric
    // add("a", "b");   // ❌ 清晰的错误:"const char*" does not satisfy Numeric
    
    square(42);         // ✅
    // square("hello"); // ❌ 清晰报错
}

1.3 requires 表达式详解

C++ 复制代码
// requires 表达式的四种要求
template <typename T>
concept Container = requires(T c, typename T::value_type v) {
    // 1. 简单要求:表达式必须合法
    c.begin();
    c.end();
    c.size();
    
    // 2. 类型要求:类型必须存在
    typename T::value_type;
    typename T::iterator;
    typename T::size_type;
    
    // 3. 复合要求:表达式合法 + 返回类型约束 + 是否 noexcept
    { c.size() } noexcept -> std::convertible_to<std::size_t>;
    { c.begin() } -> std::input_or_output_iterator;
    { *c.begin() } -> std::same_as<typename T::value_type&>;
    
    // 4. 嵌套要求:嵌套一个 requires 判断布尔条件
    requires std::default_initializable<T>;
    requires (sizeof(T) >= 8);
};

// 实际应用:约束排序算法
template <typename T>
concept Sortable = requires(T a, T b) {
    { a < b } -> std::convertible_to<bool>;
    { a = std::move(b) };
};

template <std::random_access_iterator Iter>
    requires Sortable<std::iter_value_t<Iter>>
void my_sort(Iter begin, Iter end) {
    std::sort(begin, end);
}

1.4 标准库预定义 Concepts

C++ 复制代码
#include <concepts>
#include <iterator>
#include <ranges>

/*
 *  <concepts> 中的核心概念:
 *  ┌──────────────────────────┬─────────────────────────────────┐
 *  │ 语言概念                  │ 说明                            │
 *  ├──────────────────────────┼─────────────────────────────────┤
 *  │ std::same_as<T, U>       │ T 和 U 是同一类型               │
 *  │ std::derived_from<D, B>  │ D 继承自 B                      │
 *  │ std::convertible_to<F,T> │ F 可隐式转为 T                  │
 *  │ std::integral<T>         │ T 是整数类型                     │
 *  │ std::floating_point<T>   │ T 是浮点类型                     │
 *  │ std::default_initializable│ T 可默认构造                    │
 *  │ std::copy_constructible  │ T 可拷贝构造                     │
 *  │ std::move_constructible  │ T 可移动构造                     │
 *  │ std::assignable_from     │ 可赋值                           │
 *  │ std::destructible        │ 可析构                           │
 *  ├──────────────────────────┼─────────────────────────────────┤
 *  │ 比较概念                  │                                 │
 *  ├──────────────────────────┼─────────────────────────────────┤
 *  │ std::equality_comparable │ 支持 == 和 !=                    │
 *  │ std::totally_ordered     │ 支持 <, >, <=, >=               │
 *  ├──────────────────────────┼─────────────────────────────────┤
 *  │ 可调用概念                │                                 │
 *  ├──────────────────────────┼─────────────────────────────────┤
 *  │ std::invocable<F, Args>  │ F 可用 Args 调用                │
 *  │ std::predicate<F, Args>  │ F 是返回 bool 的谓词             │
 *  │ std::relation<R, T, U>   │ R 是 T,U 上的二元关系            │
 *  └──────────────────────────┴─────────────────────────────────┘
 */

// 使用标准概念
template <std::integral T>
T gcd(T a, T b) {
    while (b != 0) { a %= b; std::swap(a, b); }
    return a;
}

void process(std::invocable<int> auto&& fn) {
    fn(42);
}

// 基于约束的重载决议
template <std::integral T>
std::string to_str(T val) { return "int:" + std::to_string(val); }

template <std::floating_point T>
std::string to_str(T val) { return "float:" + std::to_string(val); }

void overload_demo() {
    std::cout << to_str(42) << "\n";     // "int:42"
    std::cout << to_str(3.14) << "\n";   // "float:3.140000"
}

1.5 Concept 子包含(Subsumption)

C++ 复制代码
// 更受约束的 concept 优先匹配
template <typename T>
concept Animal = requires(T a) { a.breathe(); };

template <typename T>
concept Dog = Animal<T> && requires(T d) { d.bark(); };

// Dog 子包含(subsumes)Animal → Dog 更受约束

void process(Animal auto a)  { std::cout << "Animal\n"; }
void process(Dog auto d)     { std::cout << "Dog\n"; }

struct Labrador {
    void breathe() {}
    void bark() {}
};
struct Fish {
    void breathe() {}
};

void subsumption_demo() {
    process(Labrador{});   // "Dog" ← 选择更受约束的重载
    process(Fish{});       // "Animal"
}

🌊 2. Ranges(范围库)

2.1 核心理念

C++ 复制代码
/*
 *  Ranges 的核心改进:
 *  ┌──────────────────────────────────────────────────────────────┐
 *  │ 1. 算法直接接受容器(不再需要 begin/end 对)                  │
 *  │ 2. 视图(Views)实现惰性求值和管道组合                        │
 *  │ 3. 投影(Projections)替代繁琐的 Lambda                      │
 *  │ 4. 概念约束提供清晰的编译错误                                 │
 *  └──────────────────────────────────────────────────────────────┘
 */

#include <ranges>
#include <algorithm>
#include <vector>

void ranges_vs_classic() {
    std::vector<int> v = {5, 3, 1, 4, 2};
    
    // ❌ C++17 经典写法
    std::sort(v.begin(), v.end());
    auto it = std::find(v.begin(), v.end(), 3);
    
    // ✅ C++20 Ranges 写法
    std::ranges::sort(v);
    auto it2 = std::ranges::find(v, 3);
    
    // 投影(Projection)
    struct Person { std::string name; int age; };
    std::vector<Person> people = {{"Bob", 25}, {"Alice", 30}, {"Charlie", 20}};
    
    // ❌ C++17:需要写 Lambda
    std::sort(people.begin(), people.end(),
              [](const Person& a, const Person& b) { return a.age < b.age; });
    
    // ✅ C++20:使用投影
    std::ranges::sort(people, {}, &Person::age);          // 按 age 升序
    std::ranges::sort(people, std::greater{}, &Person::age);  // 按 age 降序
    
    auto youngest = std::ranges::min(people, {}, &Person::age);
}

2.2 视图(Views)与管道运算符

C++ 复制代码
#include <ranges>
#include <vector>
#include <iostream>

namespace views = std::views;  // 别名

void views_example() {
    std::vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
    // 管道语法:过滤偶数 → 平方 → 取前3个
    auto result = nums 
        | views::filter([](int n) { return n % 2 == 0; })   // {2,4,6,8,10}
        | views::transform([](int n) { return n * n; })     // {4,16,36,64,100}
        | views::take(3);                                    // {4,16,36}
    
    for (int v : result) {
        std::cout << v << " ";   // 4 16 36
    }
    std::cout << "\n";
    
    // ✅ 惰性求值!上面的链不会立即计算,遍历时才逐个处理
    // ✅ 零内存分配!视图不拷贝数据,只是"观察"原数据
}

// 常用视图适配器
void common_views() {
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
    // filter:过滤
    auto evens = v | views::filter([](int n) { return n % 2 == 0; });
    
    // transform:变换
    auto doubled = v | views::transform([](int n) { return n * 2; });
    
    // take / drop:取前N个 / 跳过前N个
    auto first3 = v | views::take(3);     // {1, 2, 3}
    auto skip3 = v | views::drop(3);      // {4, 5, 6, 7, 8, 9, 10}
    
    // take_while / drop_while:条件截取
    auto until5 = v | views::take_while([](int n) { return n < 5; });  // {1,2,3,4}
    
    // reverse:反转
    auto rev = v | views::reverse;        // {10, 9, ..., 1}
    
    // keys / values:提取 pair/tuple 的 key/value
    std::map<std::string, int> m = {{"a", 1}, {"b", 2}};
    auto keys = m | views::keys;          // {"a", "b"}
    auto vals = m | views::values;        // {1, 2}
    
    // elements<N>:提取 tuple 的第 N 个元素
    std::vector<std::tuple<int, char, double>> tuples = {{1,'a',1.1}, {2,'b',2.2}};
    auto chars = tuples | views::elements<1>;   // {'a', 'b'}
    
    // iota:生成序列
    auto numbers = views::iota(1, 11);    // {1, 2, ..., 10}
    auto infinite = views::iota(1);       // {1, 2, 3, ...} 无穷序列
    
    // 复合管道
    for (int x : views::iota(1)
                 | views::filter([](int n) { return n % 3 == 0; })
                 | views::transform([](int n) { return n * n; })
                 | views::take(5)) {
        std::cout << x << " ";   // 9 36 81 144 225
    }
    
    // split / join(字符串处理)
    std::string csv = "hello,world,foo,bar";
    for (auto word : csv | views::split(',')) {
        std::cout << std::string_view(word) << "\n";
    }
    
    // zip(C++23,但这里提一下设计思路)
    // auto zipped = views::zip(v1, v2);  // C++23
}

2.3 自定义 Range 与实际应用

C++ 复制代码
// 实际应用:数据处理管道
struct Employee {
    std::string name;
    std::string department;
    double salary;
};

void data_pipeline() {
    std::vector<Employee> employees = {
        {"Alice", "Engineering", 120000},
        {"Bob", "Marketing", 85000},
        {"Charlie", "Engineering", 95000},
        {"Diana", "Engineering", 110000},
        {"Eve", "Marketing", 92000}
    };
    
    // 找出工程部门薪资前2高的员工名
    auto top_eng_names = employees
        | views::filter([](const Employee& e) { 
            return e.department == "Engineering"; 
          })
        | views::transform(&Employee::name)
        | views::take(2);  // 注意:未排序,需先排序才有意义
    
    // 先排序再管道
    std::ranges::sort(employees, std::greater{}, &Employee::salary);
    
    for (const auto& name : employees
            | views::filter([](const Employee& e) { 
                return e.department == "Engineering"; 
              })
            | views::transform(&Employee::name)
            | views::take(2)) {
        std::cout << name << "\n";   // Alice, Diana
    }
}

🔄 3. Coroutines(协程)

3.1 协程基础概念

C++ 复制代码
/*
 *  协程 vs 普通函数:
 *  ┌───────────────┬────────────────────────────────────────────────┐
 *  │   普通函数     │ 调用 → 执行完毕 → 返回(一气呵成)                 │
 *  │   协程        │ 调用 → 暂停 → 恢复 → 暂停 → ... → 完成            │
 *  │               │ (可以在中途挂起,保留状态,稍后恢复)              │
 *  ├───────────────┼────────────────────────────────────────────────┤
 *  │   关键字       │ co_await:挂起,等待异步结果                      │
 *  │               │ co_yield:挂起,产生一个值(生成器)               │
 *  │               │ co_return:最终返回                             │
 *  ├───────────────┼────────────────────────────────────────────────┤
 *  │   应用场景     │ 异步 I/O、生成器、状态机、事件驱动                  │
 *  └───────────────┴────────────────────────────────────────────────┘
 *
 *  ⚠️ C++20 只提供了协程的底层机制(编译器支持),
 *     没有提供开箱即用的协程类型。
 *     实际使用通常借助第三方库(cppcoro)或自行实现 Promise/Awaitable。
 *     C++23 引入了 std::generator。
 */

3.2 生成器(Generator)示例

C++ 复制代码
#include <coroutine>
#include <iostream>
#include <optional>

// 最简生成器实现
template <typename T>
class Generator {
public:
    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 = std::move(value);
            return {};
        }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };
    
    // 迭代器支持(简化版)
    struct iterator {
        std::coroutine_handle<promise_type> handle_;
        bool done_;
        
        iterator& operator++() {
            handle_.resume();
            done_ = handle_.done();
            return *this;
        }
        T& operator*() { return handle_.promise().current_value; }
        bool operator!=(std::default_sentinel_t) const { return !done_; }
    };
    
    iterator begin() {
        handle_.resume();
        return {handle_, handle_.done()};
    }
    std::default_sentinel_t end() { return {}; }
    
    explicit Generator(std::coroutine_handle<promise_type> h) : handle_(h) {}
    ~Generator() { if (handle_) handle_.destroy(); }
    
    Generator(const Generator&) = delete;
    Generator(Generator&& other) noexcept : handle_(std::exchange(other.handle_, {})) {}
    
private:
    std::coroutine_handle<promise_type> handle_;
};

// ✅ 使用协程定义无穷序列
Generator<int> fibonacci() {
    int a = 0, b = 1;
    while (true) {
        co_yield a;                 // 挂起,产出当前值
        auto next = a + b;
        a = b;
        b = next;
    }
}

Generator<int> range(int start, int end) {
    for (int i = start; i < end; ++i) {
        co_yield i;
    }
}

void coroutine_demo() {
    // 惰性生成斐波那契数列
    int count = 0;
    for (int val : fibonacci()) {
        std::cout << val << " ";
        if (++count >= 10) break;
    }
    // 0 1 1 2 3 5 8 13 21 34
    
    std::cout << "\n";
    
    for (int val : range(1, 6)) {
        std::cout << val << " ";    // 1 2 3 4 5
    }
}

3.3 异步协程(Async/Await 模式)

C++ 复制代码
// 概念性示例(需要自定义 Task 类型或使用库)
/*
Task<std::string> fetch_data(std::string url) {
    auto response = co_await async_http_get(url);    // 挂起等待网络
    auto parsed = co_await async_parse(response);    // 挂起等待解析
    co_return parsed.body;
}

Task<void> process() {
    auto data1 = co_await fetch_data("https://api.example.com/a");
    auto data2 = co_await fetch_data("https://api.example.com/b");
    std::cout << data1 << ", " << data2 << "\n";
}
*/

/*
 *  协程底层机制:
 *  ┌─────────────────┬─────────────────────────────────────────┐
 *  │ coroutine_handle│ 协程句柄,用于恢复/销毁协程               │
 *  │ promise_type    │ 协程的"承诺对象",控制行为                 │
 *  │ co_await        │ 等待一个 Awaitable 对象                   │
 *  │ co_yield        │ 产出值并挂起                              │
 *  │ co_return       │ 最终返回值                                │
 *  │ Awaitable       │ 需实现 await_ready/suspend/resume         │
 *  └─────────────────┴─────────────────────────────────────────┘
 */

📦 4. Modules(模块)

C++ 复制代码
/*
 *  模块 vs 头文件:
 *  ┌───────────────┬──────────────────────┬────────────────────┐
 *  │               │    #include 头文件    │    import 模块     │
 *  ├───────────────┼──────────────────────┼────────────────────┤
 *  │ 编译速度       │ 慢(重复解析)        │ ✅ 快(预编译)    │
 *  │ 宏泄漏         │ ❌ 宏跨文件污染      │ ✅ 宏不泄漏        │
 *  │ 符号可见性     │ 全部可见             │ ✅ 显式 export     │
 *  │ include 顺序   │ ❌ 可能影响编译      │ ✅ 顺序无关        │
 *  │ ODR 违规       │ 容易出错             │ ✅ 大幅减少        │
 *  │ 编译器支持     │ 完善                 │ ⚠️ 仍在完善中      │
 *  └───────────────┴──────────────────────┴────────────────────┘
 */

// ═══ 模块接口文件:math.cppm ═══
/*
export module math;          // 声明模块名

// export 的函数/类/变量对外可见
export int add(int a, int b) {
    return a + b;
}

export class Calculator {
public:
    int multiply(int a, int b) { return a * b; }
};

// 未 export 的是模块内部实现
int internal_helper() { return 42; }   // 外部不可见
*/

// ═══ 使用模块:main.cpp ═══
/*
import math;          // 导入模块
import <iostream>;    // 导入标准头文件作为模块

int main() {
    std::cout << add(1, 2) << "\n";
    Calculator calc;
    std::cout << calc.multiply(3, 4) << "\n";
    // internal_helper();  // ❌ 错误:未 export
}
*/

// ═══ 模块分区(Module Partitions)═══
/*
// math-impl.cppm
export module math:impl;      // 模块分区
export int add(int a, int b) { return a + b; }

// math.cppm
export module math;
export import :impl;           // 重新导出分区
*/

/*
 *  ⚠️ 模块的现状(截至2024):
 *  - MSVC 支持最好
 *  - GCC/Clang 支持逐步完善
 *  - CMake 3.28+ 开始支持 C++ 模块
 *  - 大型项目迁移仍需时间
 */

⚖️ 5. 三路比较运算符(<=>,Spaceship Operator)

C++ 复制代码
#include <compare>

/*
 *  <=> 运算符返回三种比较类别之一:
 *  ┌──────────────────────┬────────────────────────────────────┐
 *  │ std::strong_ordering │ 完全有序(相等的对象不可区分)       │
 *  │                      │ 如:int, string                    │
 *  ├──────────────────────┼────────────────────────────────────┤
 *  │ std::weak_ordering   │ 弱排序(等价但可区分)              │
 *  │                      │ 如:大小写不敏感的字符串比较         │
 *  ├──────────────────────┼────────────────────────────────────┤
 *  │ std::partial_ordering│ 偏序(某些值不可比较)              │
 *  │                      │ 如:float(NaN 不可比较)           │
 *  └──────────────────────┴────────────────────────────────────┘
 */

// ❌ C++17:手动实现6个比较运算符
struct Point_old {
    int x, y;
    bool operator==(const Point_old& o) const { return x == o.x && y == o.y; }
    bool operator!=(const Point_old& o) const { return !(*this == o); }
    bool operator< (const Point_old& o) const { return std::tie(x,y) < std::tie(o.x,o.y); }
    bool operator<=(const Point_old& o) const { return !(o < *this); }
    bool operator> (const Point_old& o) const { return o < *this; }
    bool operator>=(const Point_old& o) const { return !(*this < o); }
};

// ✅ C++20:一行搞定所有比较
struct Point {
    int x, y;
    auto operator<=>(const Point&) const = default;   // 生成全部6个运算符!
};

void spaceship_basic() {
    Point a{1, 2}, b{1, 3}, c{1, 2};
    
    std::cout << (a < b) << "\n";    // true
    std::cout << (a == c) << "\n";   // true
    std::cout << (a >= b) << "\n";   // false
    
    // 直接使用 <=> 的结果
    auto cmp = a <=> b;
    if (cmp < 0) std::cout << "a < b\n";
    else if (cmp > 0) std::cout << "a > b\n";
    else std::cout << "a == b\n";
}

// 自定义比较逻辑
class Version {
    int major_, minor_, patch_;
public:
    Version(int ma, int mi, int p) : major_(ma), minor_(mi), patch_(p) {}
    
    // 自定义 <=>(按 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&) const = default;
};

void version_demo() {
    Version v1{2, 0, 0}, v2{1, 9, 9}, v3{2, 0, 0};
    std::cout << (v1 > v2) << "\n";    // true
    std::cout << (v1 == v3) << "\n";   // true
    
    // 可以直接用于排序
    std::vector<Version> versions = {{1,0,0}, {2,1,0}, {1,5,3}, {2,0,1}};
    std::ranges::sort(versions);
}

// 不同类型之间的比较
class Celsius {
    double temp_;
public:
    explicit Celsius(double t) : temp_(t) {}
    double value() const { return temp_; }
    
    std::partial_ordering operator<=>(const Celsius& other) const {
        return temp_ <=> other.temp_;   // double 的 <=> 返回 partial_ordering
    }
    bool operator==(const Celsius&) const = default;
};

🔧 6. constexpr 的全面扩展

6.1 constexpr 新能力

C++ 复制代码
#include <vector>
#include <string>
#include <algorithm>
#include <numeric>

/*
 *  C++20 constexpr 新增能力:
 *  ┌────────────────────────────┬──────┬──────┬──────┬──────┐
 *  │          特性               │ C++11│ C++14│ C++17│ C++20│
 *  ├────────────────────────────┼──────┼──────┼──────┼──────┤
 *  │ 局部变量/循环/分支          │  ❌  │  ✅  │  ✅  │  ✅  │
 *  │ virtual 函数               │  ❌  │  ❌  │  ❌  │  ✅  │
 *  │ try-catch                  │  ❌  │  ❌  │  ❌  │  ✅  │
 *  │ dynamic_cast / typeid      │  ❌  │  ❌  │  ❌  │  ✅  │
 *  │ new / delete(瞬态分配)    │  ❌  │  ❌  │  ❌  │  ✅  │
 *  │ std::vector / std::string  │  ❌  │  ❌  │  ❌  │  ✅  │
 *  │ 算法(sort/find等)         │  ❌  │  ❌  │  ❌  │  ✅  │
 *  └────────────────────────────┴──────┴──────┴──────┴──────┘
 */

// ✅ constexpr 动态内存分配(瞬态 ------ 必须在编译期释放)
constexpr int sum_of_sorted() {
    std::vector<int> v = {5, 3, 1, 4, 2};   // ✅ 编译期 vector!
    std::sort(v.begin(), v.end());            // ✅ 编译期排序!
    return std::accumulate(v.begin(), v.end(), 0);
    // v 在编译期创建和销毁(瞬态分配)
}

static_assert(sum_of_sorted() == 15);

// ✅ constexpr std::string
constexpr auto make_greeting() {
    std::string s = "Hello";
    s += ", ";
    s += "World!";
    return s.size();   // 返回 size_t(非 string 本身,因为 string 不能跨越编译期/运行期边界)
}

static_assert(make_greeting() == 13);

// ✅ constexpr virtual
struct Base {
    constexpr virtual int value() const { return 1; }
    constexpr virtual ~Base() = default;
};

struct Derived : Base {
    constexpr int value() const override { return 2; }
};

constexpr int get_value(const Base& b) { return b.value(); }

static_assert(get_value(Derived{}) == 2);

6.2 consteval ------ 强制编译期求值

C++ 复制代码
// consteval:函数必须在编译期求值,不能在运行期调用
consteval int compile_time_square(int x) {
    return x * x;
}

void consteval_example() {
    constexpr int a = compile_time_square(5);   // ✅ 编译期
    // int x = 5;
    // int b = compile_time_square(x);          // ❌ 错误:x 不是编译期常量
    
    const int c = compile_time_square(10);      // ✅ 编译期(const + 常量表达式)
}

// 实际应用:编译期校验
consteval int safe_divide(int a, int b) {
    if (b == 0) throw "Division by zero!";   // 编译期抛出 → 编译错误
    return a / b;
}

constexpr int r1 = safe_divide(10, 2);   // ✅ OK = 5
// constexpr int r2 = safe_divide(10, 0);  // ❌ 编译错误!

// consteval 用于生成只在编译期存在的数据
consteval auto create_lookup_table() {
    std::array<int, 256> table{};
    for (int i = 0; i < 256; ++i) {
        table[i] = (i * i) % 256;
    }
    return table;
}

constexpr auto lookup = create_lookup_table();   // 编译期生成查找表

6.3 constinit ------ 保证静态初始化

C++ 复制代码
// constinit:保证变量在编译期初始化,但不要求变量是 const
// 解决"静态初始化顺序惨败"(Static Initialization Order Fiasco)

constinit int global_count = 0;          // ✅ 编译期初始化为 0
// constinit int bad = rand();           // ❌ 错误:rand() 不是常量表达式

constinit thread_local int tls_val = 42; // ✅ 线程局部变量也可以

void constinit_example() {
    global_count = 100;   // ✅ 运行期可以修改(不是 const)
    
    // 与 constexpr 的区别:
    // constexpr → 编译期初始化 + 不可修改
    // constinit → 编译期初始化 + 可以修改
}

/*
 *  三者对比:
 *  ┌──────────┬──────────────────┬───────────────┬───────────────┐
 *  │          │ 编译期初始化       │ 编译期可用     │ 运行期可修改   │
 *  ├──────────┼──────────────────┼───────────────┼───────────────┤
 *  │ const    │ 不保证            │ 不保证         │ ❌            │
 *  │ constexpr│ ✅ 保证           │ ✅            │ ❌            │
 *  │ constinit│ ✅ 保证           │ ❌            │ ✅            │
 *  │ consteval│ ---(用于函数)      │ ✅ 强制       │ ---             │
 *  └──────────┴──────────────────┴───────────────┴───────────────┘
 */

📝 7. std::format ------ 现代格式化

C++ 复制代码
#include <format>
#include <string>
#include <iostream>

/*
 *  std::format vs printf vs iostream:
 *  ┌────────────┬───────────┬───────────┬────────────────┐
 *  │            │  printf   │ iostream  │ std::format     │
 *  ├────────────┼───────────┼───────────┼────────────────┤
 *  │ 类型安全    │ ❌        │ ✅        │ ✅              │
 *  │ 可扩展      │ ❌        │ ✅ (<<)   │ ✅ (formatter) │
 *  │ 性能        │ ✅ 快     │ ❌ 慢     │ ✅ 快          │
 *  │ 可读性      │ ⚠️ 一般  │ ❌ 链式差  │ ✅ 最好        │
 *  │ 本地化      │ ⚠️       │ ✅        │ ✅              │
 *  └────────────┴───────────┴───────────┴────────────────┘
 */

void format_basic() {
    // 基本用法
    std::string s = std::format("Hello, {}!", "World");
    std::cout << s << "\n";   // "Hello, World!"
    
    // 多个参数
    std::string info = std::format("{} is {} years old", "Alice", 30);
    
    // 位置参数
    std::string ordered = std::format("{1} before {0}", "World", "Hello");
    // "Hello before World"
    
    // 格式规范
    std::cout << std::format("{:>10}", "right") << "\n";     // "     right"(右对齐)
    std::cout << std::format("{:<10}", "left") << "\n";      // "left      "(左对齐)
    std::cout << std::format("{:^10}", "center") << "\n";    // "  center  "(居中)
    std::cout << std::format("{:*^10}", "hi") << "\n";       // "****hi****"(填充字符)
    
    // 数字格式
    std::cout << std::format("{:d}", 42) << "\n";        // "42"(十进制)
    std::cout << std::format("{:x}", 255) << "\n";       // "ff"(十六进制)
    std::cout << std::format("{:#x}", 255) << "\n";      // "0xff"
    std::cout << std::format("{:b}", 42) << "\n";        // "101010"(二进制)
    std::cout << std::format("{:#010b}", 42) << "\n";    // "0b00101010"
    std::cout << std::format("{:o}", 42) << "\n";        // "52"(八进制)
    
    // 浮点格式
    std::cout << std::format("{:.2f}", 3.14159) << "\n";    // "3.14"
    std::cout << std::format("{:e}", 12345.6) << "\n";      // "1.234560e+04"
    std::cout << std::format("{:10.3f}", 3.14) << "\n";     // "     3.140"
    
    // 直接输出(C++23 有 std::print,C++20 用 format + cout)
    std::cout << std::format("x={}, y={}, z={}\n", 1, 2.5, "three");
}

// 自定义类型的格式化支持
struct Point {
    double x, y;
};

template <>
struct std::formatter<Point> {
    constexpr auto parse(std::format_parse_context& ctx) {
        return ctx.begin();
    }
    
    auto format(const Point& p, std::format_context& ctx) const {
        return std::format_to(ctx.out(), "({:.2f}, {:.2f})", p.x, p.y);
    }
};

void custom_format() {
    Point p{1.5, 2.7};
    std::cout << std::format("Point: {}\n", p);   // "Point: (1.50, 2.70)"
}

🔍 8. std::span ------ 连续内存的非拥有视图

C++ 复制代码
#include <span>
#include <vector>
#include <array>

/*
 *  std::span<T>:对连续内存的非拥有、轻量级视图
 *  ┌────────────────┬──────────────────────────────────────────────┐
 *  │ 类比           │ string_view 之于 string,span 之于 vector    │
 *  │ 大小           │ 指针 + 长度(16字节)                         │
 *  │ 可以指向       │ C数组、vector、array、new[] 等连续内存         │
 *  │ 静态/动态      │ span<T, N>(编译期大小)/ span<T>(运行时大小)│
 *  └────────────────┴──────────────────────────────────────────────┘
 */

// ❌ C++17:接受数组的函数需要多个重载或模板
void process_old(const int* data, size_t size) { /* C风格 */ }
void process_old(const std::vector<int>& v) { /* vector */ }
template<size_t N> void process_old(const std::array<int, N>& a) { /* array */ }

// ✅ C++20:span 统一所有连续容器
void process(std::span<const int> data) {
    for (int val : data) {
        std::cout << val << " ";
    }
    std::cout << "\n";
    
    // 丰富的操作
    auto first3 = data.first(3);          // 前3个元素的子 span
    auto last2 = data.last(2);            // 后2个元素的子 span
    auto mid = data.subspan(1, 3);        // 从索引1开始取3个
    
    std::cout << "Size: " << data.size() << "\n";
    std::cout << "Empty: " << data.empty() << "\n";
    std::cout << "Front: " << data.front() << "\n";
    std::cout << "Back: " << data.back() << "\n";
    std::cout << "[2]: " << data[2] << "\n";
}

void span_usage() {
    // 同一个函数接受所有连续容器
    int c_arr[] = {1, 2, 3, 4, 5};
    std::vector<int> vec = {10, 20, 30};
    std::array<int, 4> arr = {100, 200, 300, 400};
    
    process(c_arr);    // ✅ C 数组
    process(vec);      // ✅ vector
    process(arr);      // ✅ array
}

// 可修改的 span
void modify(std::span<int> data) {
    for (auto& val : data) {
        val *= 2;
    }
}

// 静态大小的 span(编译期已知大小)
void fixed_size(std::span<int, 3> triple) {
    // 保证恰好3个元素
    std::cout << triple[0] + triple[1] + triple[2] << "\n";
}

void static_span_demo() {
    int arr[] = {1, 2, 3, 4, 5};
    // fixed_size(arr);          // ❌ 大小不匹配(5 != 3)
    fixed_size({arr, 3});        // ✅ 取前3个
    
    std::span<int, 3> s(arr, 3);  // ✅ 显式构造
    fixed_size(s);
}

// 二维数据处理
void process_matrix(std::span<const std::span<const int>> rows) {
    for (auto row : rows) {
        for (int val : row) {
            std::cout << val << " ";
        }
        std::cout << "\n";
    }
}

9. 日历与时区(<chrono> 增强)

C++ 复制代码
#include <chrono>
#include <iostream>

namespace chrono = std::chrono;

void calendar_example() {
    // ═══ 日历类型 ═══
    using namespace chrono;
    
    // 创建日期
    auto today = year{2024}/December/25;          // 2024-12-25
    auto same = year_month_day{year{2024}, month{12}, day{25}};
    auto also = 2024y/12/25d;                      // 字面量语法
    
    // 日期查询
    std::cout << "Valid: " << today.ok() << "\n";   // true
    std::cout << "Year: " << (int)today.year() << "\n";
    std::cout << "Month: " << (unsigned)today.month() << "\n";
    std::cout << "Day: " << (unsigned)today.day() << "\n";
    
    // 星期几
    auto wd = weekday{sys_days{today}};
    std::cout << "Weekday: " << wd << "\n";         // Wed
    
    // 特殊日期
    auto first_monday = year{2024}/January/Monday[1];     // 2024年1月第一个周一
    auto last_friday = year{2024}/March/Friday[last];     // 2024年3月最后一个周五
    
    // 日期运算
    auto next_month = today + months{1};
    auto next_year = today + years{1};
    
    // 年月的最后一天
    auto end_of_feb = year{2024}/February/last;   // 2024-02-29(闰年)
}

void timezone_example() {
    using namespace chrono;
    
    // 当前时间(UTC)
    auto now_utc = system_clock::now();
    
    // 转换为本地时间
    auto now_local = zoned_time{current_zone(), now_utc};
    std::cout << "Local: " << now_local << "\n";
    
    // 指定时区
    auto tokyo = zoned_time{"Asia/Tokyo", now_utc};
    auto nyc = zoned_time{"America/New_York", now_utc};
    
    std::cout << "Tokyo: " << tokyo << "\n";
    std::cout << "NYC:   " << nyc << "\n";
    
    // 时区转换
    auto meeting_nyc = zoned_time{"America/New_York", 
        local_days{2024y/June/15} + 14h};   // 纽约时间 6月15日 14:00
    auto meeting_tokyo = zoned_time{"Asia/Tokyo", meeting_nyc};
    std::cout << "Meeting in Tokyo: " << meeting_tokyo << "\n";
}

// 高精度计时增强
void timing_enhanced() {
    using namespace chrono;
    
    // 日/周/月/年 时间单位
    auto one_day = days{1};
    auto two_weeks = weeks{2};
    
    // hh_mm_ss:时分秒解析
    auto duration = 3723s;   // 3723 秒
    hh_mm_ss hms{duration};
    std::cout << hms.hours() << "h "
              << hms.minutes() << "m "
              << hms.seconds() << "s\n";   // 1h 2m 3s
}

🧵 10. 并发增强

10.1 std::jthread 与协作式取消

C++ 复制代码
#include <thread>
#include <stop_token>

// ❌ C++17 std::thread 的问题:
// 1. 忘记 join() 会 std::terminate
// 2. 无标准化的取消机制

// ✅ C++20 std::jthread:自动 join + 支持取消
void jthread_example() {
    // 析构时自动 join(J = Joining Thread)
    {
        std::jthread t([]() {
            std::cout << "Working...\n";
        });
        // 作用域结束 → 自动 join,不会 terminate
    }
    
    // 协作式取消
    std::jthread worker([](std::stop_token stoken) {
        while (!stoken.stop_requested()) {     // 检查是否被请求停止
            std::cout << "Working...\n";
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
        std::cout << "Stopped gracefully.\n";
    });
    
    std::this_thread::sleep_for(std::chrono::milliseconds(350));
    worker.request_stop();   // 请求线程停止
    // worker 析构时自动 join
    
    // stop_callback:注册取消时的回调
    std::jthread t2([](std::stop_token st) {
        std::stop_callback callback(st, []() {
            std::cout << "Cleanup on cancel!\n";
        });
        
        while (!st.stop_requested()) {
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
        }
    });
    
    t2.request_stop();   // 触发回调 + 线程退出
}

10.2 新增同步原语

C++ 复制代码
#include <semaphore>
#include <latch>
#include <barrier>

// ═══ std::counting_semaphore / std::binary_semaphore ═══
void semaphore_example() {
    // 限制并发数为 3
    std::counting_semaphore<3> sem(3);
    
    auto worker = [&sem](int id) {
        sem.acquire();   // P 操作(阻塞直到 > 0,然后 -1)
        std::cout << "Thread " << id << " working\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        sem.release();   // V 操作(+1)
    };
    
    std::vector<std::jthread> threads;
    for (int i = 0; i < 10; ++i)
        threads.emplace_back(worker, i);
    // 最多 3 个线程同时执行
    
    // binary_semaphore = counting_semaphore<1>
    std::binary_semaphore gate(0);   // 初始值 0(阻塞)
    std::jthread t([&gate]() {
        gate.acquire();              // 等待信号
        std::cout << "Gate opened!\n";
    });
    gate.release();                  // 发送信号
}

// ═══ std::latch(一次性屏障)═══
void latch_example() {
    constexpr int N = 5;
    std::latch start_latch(1);      // 所有线程等待开始信号
    std::latch done_latch(N);       // 主线程等待所有子线程完成
    
    std::vector<std::jthread> workers;
    for (int i = 0; i < N; ++i) {
        workers.emplace_back([&, i]() {
            start_latch.wait();      // 等待开始
            std::cout << "Worker " << i << " running\n";
            done_latch.count_down(); // 标记完成
        });
    }
    
    start_latch.count_down();        // 发出开始信号
    done_latch.wait();               // 等待所有完成
    std::cout << "All workers done!\n";
}

// ═══ std::barrier(可复用屏障)═══
void barrier_example() {
    constexpr int N = 3;
    int phase = 0;
    
    std::barrier sync_point(N, [&]() noexcept {
        // 所有线程到达后执行的回调
        ++phase;
        std::cout << "=== Phase " << phase << " complete ===\n";
    });
    
    auto worker = [&](int id) {
        for (int i = 0; i < 3; ++i) {
            std::cout << "Thread " << id << " phase " << i << "\n";
            sync_point.arrive_and_wait();   // 等待所有线程到达
        }
    };
    
    std::vector<std::jthread> threads;
    for (int i = 0; i < N; ++i)
        threads.emplace_back(worker, i);
}

// ═══ std::atomic 增强 ═══
// atomic<shared_ptr>、atomic<weak_ptr>、atomic 等待/通知
void atomic_wait_example() {
    std::atomic<int> value{0};
    
    std::jthread producer([&value]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        value.store(42);
        value.notify_one();   // ✅ C++20:原子通知
    });
    
    value.wait(0);   // ✅ C++20:原子等待(阻塞直到值不等于 0)
    std::cout << "Got: " << value.load() << "\n";   // 42
}

🏗️ 11. 语言特性增强

11.1 指定初始化器(Designated Initializers)

C++ 复制代码
struct Config {
    int width = 800;
    int height = 600;
    bool fullscreen = false;
    std::string title = "App";
    double fps = 60.0;
};

void designated_init() {
    // ✅ C++20:按名称初始化成员(必须按声明顺序)
    Config cfg = {
        .width = 1920,
        .height = 1080,
        .fullscreen = true,
        // title 使用默认值 "App"
        .fps = 144.0
    };
    
    // 极大提高可读性(特别是有很多参数时)
    // 对比 C++17:Config cfg{1920, 1080, true, "App", 144.0};  // 哪个是什么?
    
    // ⚠️ 顺序必须与声明一致
    // Config bad = {.height = 100, .width = 200};  // ❌ 顺序错误
    
    // ⚠️ 不能混用指定和非指定
    // Config bad2 = {1920, .fullscreen = true};    // ❌
}

11.2 using enum

C++ 复制代码
enum class Color { Red, Green, Blue };
enum class Permission { Read = 1, Write = 2, Execute = 4 };

void using_enum_example() {
    // ❌ C++17:枚举值需要带前缀
    Color c = Color::Red;
    
    // ✅ C++20:using enum 引入所有枚举值
    using enum Color;
    Color c2 = Red;       // ✅ 直接使用
    
    // 常用于 switch
    switch (c2) {
        using enum Color;
        case Red:   std::cout << "Red\n"; break;
        case Green: std::cout << "Green\n"; break;
        case Blue:  std::cout << "Blue\n"; break;
    }
}

11.3 模板增强

C++ 复制代码
// ═══ 简写函数模板(Abbreviated Function Templates)═══
// 函数参数中的 auto 等价于模板参数
void print(auto const& value) {
    std::cout << value << "\n";
}
// 等价于:
// template <typename T> void print(const T& value) { ... }

// 带约束的简写
void process(std::integral auto x) {
    std::cout << x * 2 << "\n";
}

// ═══ 非类型模板参数增强 ═══
// C++20 允许浮点数和字面量类类型作为非类型模板参数
template <double Value>
struct FloatConstant {
    static constexpr double value = Value;
};

FloatConstant<3.14> pi_const;

// 字面量类类型作为 NTTP
struct FixedString {
    char data[32]{};
    consteval FixedString(const char* s) {
        for (int i = 0; s[i]; ++i) data[i] = s[i];
    }
};

template <FixedString Name>
struct NamedType {
    static constexpr auto name = Name.data;
};

NamedType<"velocity"> vel;   // ✅ 字符串字面量作为模板参数!
static_assert(vel.name[0] == 'v');

// ═══ Lambda 增强 ═══
// 模板 Lambda
auto generic = []<typename T>(std::vector<T>& v) {
    // 可以使用 T
    T sum{};
    for (const auto& elem : v) sum += elem;
    return sum;
};

// Lambda 可默认构造和赋值(无状态 Lambda)
auto cmp = [](int a, int b) { return a < b; };
decltype(cmp) another;   // ✅ C++20 允许默认构造无状态 Lambda

// 显式 this 参数(Deducing this, 实际是 C++23,但概念在 C++20 讨论)

11.4 [[likely]][[unlikely]]

C++ 复制代码
// 向编译器提示分支的可能性,帮助优化
int process_request(int type) {
    if (type == 0) [[unlikely]] {
        // 错误处理路径(极少执行)
        return handle_error();
    }
    
    if (type == 1) [[likely]] {
        // 热路径(最常执行)
        return fast_path();
    }
    
    return default_path();
}

// switch 中使用
void dispatch(int code) {
    switch (code) {
        [[likely]]   case 200: handle_ok(); break;
        [[unlikely]] case 500: handle_error(); break;
        default: handle_other(); break;
    }
}

11.5 [[no_unique_address]]

C++ 复制代码
// 允许空成员不占用存储空间(Empty Base Optimization 的成员版)
struct Empty {};

// ❌ C++17:空成员仍占用至少 1 字节
struct OldHolder {
    Empty e;     // 1 字节(加上对齐可能更多)
    int value;   // 4 字节
    // sizeof = 8(含对齐)
};

// ✅ C++20:空成员可以不占空间
struct NewHolder {
    [[no_unique_address]] Empty e;   // 0 字节!
    int value;                       // 4 字节
    // sizeof = 4
};

// 实际应用:存储无状态的分配器/比较器/删除器时节省空间
template <typename T, typename Deleter = std::default_delete<T>>
class CompactPtr {
    T* ptr_;
    [[no_unique_address]] Deleter deleter_;   // 无状态时不占空间
public:
    ~CompactPtr() { deleter_(ptr_); }
};
// sizeof(CompactPtr<int>) == sizeof(int*)  // ✅ 与裸指针一样大

11.6 立即函数中的 constevalis_constant_evaluated()

C++ 复制代码
#include <type_traits>

constexpr int compute(int x) {
    if (std::is_constant_evaluated()) {
        // 编译期路径(可以做更安全但更慢的实现)
        return x * x;
    } else {
        // 运行期路径(可以用硬件加速等)
        return x * x;  // 实际可调用非 constexpr 函数
    }
}

void is_ce_demo() {
    constexpr int a = compute(5);   // 走编译期路径
    int x = 5;
    int b = compute(x);             // 走运行期路径
}

📚 12. 标准库其他增强

12.1 std::source_location

C++ 复制代码
#include <source_location>

// 替代 __FILE__、__LINE__、__func__
void log(const std::string& message,
         const std::source_location& loc = std::source_location::current()) {
    std::cout << loc.file_name() << ":" 
              << loc.line() << " ["
              << loc.function_name() << "] "
              << message << "\n";
}

void source_location_demo() {
    log("Something happened");
    // 输出:main.cpp:42 [source_location_demo] Something happened
    
    // 比宏更安全、更灵活、支持默认参数
}

12.2 std::bit_cast

C++ 复制代码
#include <bit>

// 类型安全的位级重新解释(替代 reinterpret_cast / memcpy)
void bit_cast_example() {
    float f = 3.14f;
    
    // ❌ reinterpret_cast 是未定义行为
    // int bad = *reinterpret_cast<int*>(&f);
    
    // ✅ C++20:std::bit_cast
    auto i = std::bit_cast<uint32_t>(f);
    std::cout << std::format("Float {:.2f} = 0x{:08X}\n", f, i);
    
    // 反向转换
    float f2 = std::bit_cast<float>(i);
    
    // constexpr 安全
    static_assert(std::bit_cast<uint32_t>(1.0f) == 0x3F800000);
}

// 其他 <bit> 工具
void bit_utils() {
    unsigned x = 0b0101'1010;
    
    std::cout << std::popcount(x) << "\n";       // 4(1的个数)
    std::cout << std::countl_zero(x) << "\n";    // 前导零数量
    std::cout << std::countr_zero(x) << "\n";    // 尾随零数量
    std::cout << std::has_single_bit(8u) << "\n"; // true(是2的幂)
    std::cout << std::bit_ceil(5u) << "\n";       // 8(向上取2的幂)
    std::cout << std::bit_floor(5u) << "\n";      // 4(向下取2的幂)
    std::cout << std::bit_width(5u) << "\n";      // 3(表示5需要的位数)
    std::cout << std::rotl(x, 2) << "\n";         // 循环左移
    std::cout << std::rotr(x, 2) << "\n";         // 循环右移
}

12.3 容器与字符串增强

C++ 复制代码
void container_enhancements() {
    // ═══ starts_with / ends_with(string / string_view)═══
    std::string url = "https://example.com/api/data";
    
    if (url.starts_with("https://")) {
        std::cout << "Secure URL\n";
    }
    if (url.ends_with("/data")) {
        std::cout << "Data endpoint\n";
    }
    
    // ═══ contains()(关联容器)═══
    std::map<std::string, int> scores = {{"Alice", 90}, {"Bob", 85}};
    
    // ❌ C++17
    if (scores.count("Alice") > 0) { /* ... */ }
    if (scores.find("Alice") != scores.end()) { /* ... */ }
    
    // ✅ C++20
    if (scores.contains("Alice")) {
        std::cout << "Found Alice\n";
    }
    
    // set 也支持
    std::set<int> s = {1, 2, 3, 4, 5};
    std::cout << s.contains(3) << "\n";   // true
    
    // ═══ std::erase / std::erase_if(统一容器擦除)═══
    std::vector<int> v = {1, 2, 3, 2, 4, 2, 5};
    
    // ❌ C++17:erase-remove idiom
    v.erase(std::remove(v.begin(), v.end(), 2), v.end());
    
    // ✅ C++20:一行搞定
    std::vector<int> v2 = {1, 2, 3, 2, 4, 2, 5};
    std::erase(v2, 2);                    // 删除所有 2
    std::erase_if(v2, [](int x) { return x > 3; });  // 删除所有大于3的
    
    // 适用于所有标准容器
    std::list<int> lst = {1, 2, 3, 4, 5};
    std::erase_if(lst, [](int x) { return x % 2 == 0; });
    
    std::map<std::string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}};
    std::erase_if(m, [](const auto& pair) { return pair.second < 2; });
}

// ═══ std::to_array ═══
void to_array_example() {
    // C 数组 → std::array
    auto arr = std::to_array({1, 2, 3, 4, 5});   // std::array<int, 5>
    
    // 字符串数组
    auto strs = std::to_array<std::string>({"hello", "world"});
    
    // 移动语义
    auto ptrs = std::to_array({
        std::make_unique<int>(1),
        std::make_unique<int>(2)
    });
}

// ═══ std::midpoint / std::lerp ═══
#include <numeric>
#include <cmath>

void math_additions() {
    // 安全的中点计算(不会溢出)
    int a = 2'000'000'000, b = 2'000'000'000;
    int mid = std::midpoint(a, b);   // ✅ 正确,不会整数溢出
    // (a + b) / 2 会溢出!
    
    // 线性插值
    double result = std::lerp(0.0, 10.0, 0.3);   // 3.0
    // lerp(a, b, t) = a + t * (b - a)
}

// ═══ std::make_shared 支持数组(C++20)═══
void shared_array() {
    auto arr = std::make_shared<int[]>(10);       // 10个int的数组
    arr[0] = 42;
    
    auto arr2 = std::make_shared<int[5]>();        // 固定大小5
}

12.4 std::atomic_ref

C++ 复制代码
#include <atomic>

// 对非原子对象提供原子操作
void atomic_ref_example() {
    int normal_int = 0;   // 普通 int,非 atomic
    
    auto increment = [&normal_int]() {
        // 创建原子引用来安全操作
        std::atomic_ref<int> ref(normal_int);
        for (int i = 0; i < 10000; ++i) {
            ref.fetch_add(1, std::memory_order_relaxed);
        }
    };
    
    std::jthread t1(increment);
    std::jthread t2(increment);
    t1.join();
    t2.join();
    
    std::cout << normal_int << "\n";   // 20000(精确)
    
    // 用途:对结构体中的某个字段进行原子操作
    // 无需将整个结构体变为 atomic
}

📊 13. 综合特性速查表

C++

复制代码
┌──────────────────────┬───────────────────────────────────────────────────────┐
│       特性分类        │                    具体特性                            │
├──────────────────────┼───────────────────────────────────────────────────────┤
│  四大旗舰            │                                                       │
│   Concepts           │ concept 定义, requires 表达式, 约束重载决议             │
│   Ranges             │ 管道语法, views 惰性视图, 投影, ranges 算法            │
│   Coroutines         │ co_await, co_yield, co_return, promise_type           │
│   Modules            │ export module, import, 模块分区                       │
├──────────────────────┼───────────────────────────────────────────────────────┤
│  比较运算             │ <=> 三路比较, auto operator<=>(...) = default            │
├──────────────────────┼───────────────────────────────────────────────────────┤
│  编译期计算            │ constexpr 虚函数/动态分配/try-catch/vector/string     │
│                      │ consteval 强制编译期                                   │
│                      │ constinit 保证静态初始化                               │
│                      │ is_constant_evaluated()                               │
├──────────────────────┼───────────────────────────────────────────────────────┤
│  格式化               │ std::format 类 Python 格式化                          │
├──────────────────────┼───────────────────────────────────────────────────────┤
│  视图类型             │ std::span 连续内存视图                                 │
├──────────────────────┼───────────────────────────────────────────────────────┤
│  时间日期             │ 日历类型(year/month/day)、时区(zoned_time)             │
├──────────────────────┼───────────────────────────────────────────────────────┤
│  并发                 │ jthread + stop_token 协作取消                          │
│                      │ semaphore, latch, barrier                             │
│                      │ atomic::wait/notify, atomic_ref                       │
├──────────────────────┼───────────────────────────────────────────────────────┤
│  语法增强             │ 指定初始化器 {.x=1}                                    │
│                      │ using enum                                            │
│                      │ 简写函数模板 (auto 参数)                               │
│                      │ 非类型模板参数 (浮点/字面量类)                          │
│                      │ 模板 Lambda []<typename T>(...)                         │
│                      │ constexpr Lambda                                      │
├──────────────────────┼───────────────────────────────────────────────────────┤
│  属性                 │ [[likely]], [[unlikely]]                              │
│                      │ [[no_unique_address]]                                 │
├──────────────────────┼───────────────────────────────────────────────────────┤
│  标准库工具           │ source_location, bit_cast, bit 操作                   │
│                      │ starts_with/ends_with, contains()                     │
│                      │ std::erase/erase_if, to_array                        │
│                      │ midpoint, lerp                                        │
│                      │ make_shared<T[]>                                      │
└──────────────────────┴───────────────────────────────────────────────────────┘

💡 与 C++11/14/17 的演进关系

C++

复制代码
┌─────────────────────────────────────────────────────────────────────────┐
│                  C++17 → C++20 演进关系                                  │
├──────────────────────────┬──────────────────────────────────────────────┤
│  C++17 及之前的痛点       │         C++20 的改进                         │
├──────────────────────────┼──────────────────────────────────────────────┤
│ 模板错误信息不可读          │ ✅ Concepts:约束显式化,错误信息清晰         │
│ SFINAE/enable_if 复杂     │                                              │
├──────────────────────────┼──────────────────────────────────────────────┤
│ 算法需要 begin/end 对      │ ✅ Ranges:直接传容器 + 惰性管道组合         │
│ 无惰性求值/管道组合         │                                              │
├──────────────────────────┼──────────────────────────────────────────────┤
│ 无标准协程支持             │ ✅ Coroutines:co_await/yield/return         │
├──────────────────────────┼──────────────────────────────────────────────┤
│ #include 编译慢/宏污染     │ ✅ Modules:预编译、无宏泄漏                 │
├──────────────────────────┼──────────────────────────────────────────────┤
│ 手写6个比较运算符          │ ✅ <=> 一行生成全部                          │
├──────────────────────────┼──────────────────────────────────────────────┤
│ constexpr 不能用 vector   │ ✅ constexpr 动态分配 + STL 容器              │
├──────────────────────────┼──────────────────────────────────────────────┤
│ printf 不安全,cout 太慢   │ ✅ std::format 安全+快速+可读                │
├──────────────────────────┼──────────────────────────────────────────────┤
│ 接受数组参数需多个重载      │ ✅ std::span 统一连续容器                    │
├──────────────────────────┼──────────────────────────────────────────────┤
│ 无标准日期/时区 API        │ ✅ chrono 日历 + 时区                        │
├──────────────────────────┼──────────────────────────────────────────────┤
│ thread 忘记 join 则崩溃   │ ✅ jthread 自动 join + 协作取消              │
│ 无标准化取消机制           │                                              │
├──────────────────────────┼──────────────────────────────────────────────┤
│ erase-remove 惯用法繁琐   │ ✅ std::erase / std::erase_if 一行删除       │
├──────────────────────────┼──────────────────────────────────────────────┤
│ map.count / find 判断存在 │ ✅ map.contains() 语义清晰                   │
├──────────────────────────┼──────────────────────────────────────────────┤
│ 聚合初始化不知道哪个是哪个   │ ✅ 指定初始化器 {.width=100, .height=200}    │
└──────────────────────────┴──────────────────────────────────────────────┘

💡 关键实践原则

  1. 用 Concepts 替代 SFINAE / enable_if
    • 模板约束显式化,错误信息对人友好
    • 优先使用标准库预定义 concepts(std::integralstd::invocable 等)
    • 简写语法 void f(std::integral auto x) 最为简洁
  2. 用 Ranges 管道替代手写循环和 begin/end 对
    • views::filter | views::transform | views::take 声明式编程
    • 惰性求值 + 零分配,性能不打折
    • 投影参数避免包装 Lambda
  3. <=> 一行完成所有比较运算符
    • 新写的类都应该使用 auto operator<=>(...) const = default
    • 自定义逻辑时注意同时声明 operator==
  4. std::format 替代 printf 和 iostream 拼接
    • 类型安全 + 高性能 + 可读性最佳
    • 为自定义类型特化 std::formatter
  5. std::span 统一接受连续内存参数
    • 替代 (T* ptr, size_t len)const vector<T>&
    • ⚠️ 注意生命周期(同 string_view
  6. std::jthread + stop_token 替代 std::thread
    • 自动 join 避免忘记导致 terminate
    • 标准化的协作式取消机制
  7. 充分利用 constexpr 的全面扩展
    • 编译期使用 vectorstring、算法
    • consteval 强制编译期计算,constinit 防止静态初始化顺序问题
  8. contains()starts_with()std::erase_if 简化常见操作
    • 这些 API 让代码意图更直接,减少样板代码

总结

C++20 是自 C++11 以来最具变革意义的版本,四大旗舰特性从根本上改变了 C++ 的编程范式。Concepts 让模板编程从"黑魔法"走向"可读可维护";Ranges 将函数式编程的管道组合引入 C++,实现了声明式的数据处理;Coroutines 为异步编程和生成器提供了底层支持;Modules 开启了告别 #include 的新时代。

除四大旗舰外,三路比较运算符 消灭了样板比较代码,constexpr 的全面扩展 让编译期计算达到了前所未有的能力,**std::format**终结了格式化输出的安全与性能之争,并发原语jthreadsemaphorelatchbarrier)补齐了多线程编程的基础设施。

C++20 的设计目标是"让简单的事情简单,让复杂的事情成为可能,让错误的事情难以发生"。掌握 C++20 不仅是技术能力的提升,更是编程思维的飞跃------从过程式到声明式,从运行期到编译期,从手动管理到自动安全。它为 C++ 在系统编程、高性能计算、嵌入式、游戏引擎等领域继续保持统治地位奠定了坚实的现代化基础。

相关推荐
枫叶机关录2 小时前
算法笔记:K-means、K-means++与K-Medoids聚类算法--详解、案例分析
算法·聚类·k-means
贾斯汀玛尔斯2 小时前
每天学一个算法-- 归并排序(Merge Sort)
数据结构·算法·排序算法
算法鑫探2 小时前
算法中的二分法(二分查找)详解及示例
c语言·数据结构·算法·新人首发
叶子野格2 小时前
《C语言学习:编程例题》8
c语言·开发语言·c++·学习·算法·visual studio
澈2072 小时前
排序算法入门:冒泡、选择、插入排序详解
数据结构·算法·排序算法
smj2302_796826522 小时前
解决leetcode第3901题好子序列查询
python·算法·leetcode
_深海凉_2 小时前
LeetCode热题100-每日温度
算法·leetcode·职场和发展
迷你可可小生2 小时前
面经学习(二)
学习·算法
John.Lewis2 小时前
C++加餐课-二叉树:进阶算法
数据结构·c++·算法