C++20 新特性笔记

C++20 标准概述

C++20是C++语言的一次重大更新,引入了多项核心特性以提升开发效率和代码表现力。模块系统(Modules)替代传统头文件机制,改善编译速度与隔离性;概念(Concepts)为模板编程提供类型约束的直观语法;协程(Coroutines)支持异步编程的简化实现;范围库(Ranges)提供声明式数据操作管道;三向比较运算符(<=>)统一比较逻辑;日历与时区扩展()增强时间处理能力。此外,constexpr支持更多运行时计算,结构化绑定可作用于普通数组,原子操作新增等待通知机制。这些特性共同强化了C++在泛型编程、并发处理和代码组织方面的现代化能力。

🧱 一、VsCode配置C++20编译环境

  • 下载最新版的 MinGW64 安装并配置 bin 目录到环境变量 path 中
  • 配置 task.json,加上参数 -std=c++20
{
    "tasks": [
        {
            "type": "cppbuild",
            "label": "C/C++: g++.exe build active file",
            "command": "D:\\DevelopApps\\mingw64\\bin\\g++.exe",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "-std=c++20", // 添加此行
                "${file}",
                "-o",
                "${fileDirname}\\${fileBasenameNoExtension}.exe"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "Task generated by Debugger."
        }
    ],
    "version": "2.0.0"
}

🧱 二、核心语言特性

1. 模块 (Modules)

  • 目标: 解决传统头文件(#include)机制带来的问题(编译速度慢、宏污染、包含顺序依赖、语义不明确)。
  • 核心: 将代码划分为独立的、预编译的模块单元(.ixx, .cppm, .cpp)。
  • 关键字: module, export, import
  • 优点:
    • 显著提升编译速度: 模块接口只编译一次,导入时不需重新解析。
    • 强隔离性: 模块内非导出内容对外完全不可见(无宏泄露、无私有声明污染)。
    • 消除包含顺序依赖: 导入顺序无关紧要。
    • 更清晰的语义: 明确区分接口(export)与实现。
  • 常考/常用: 是 C++20 最重要的特性之一,未来项目的基础构建方式,面试常问其优点和基本用法。
  • 示例
    	// math.cppm - 模块接口文件
    	export module math;
    	
    	export int add(int a, int b) {
    	    return a + b;
    	}
    	
    	export constexpr double pi = 3.1415926;
    	```
    		  
    
    	```cpp
    	// main.cpp - 主程序
    	import math;  // 导入模块
    	#include <iostream>
    	
    	int main() {
    	    std::cout << "2 + 3 = " << add(2, 3) << std::endl;
    	    std::cout << "π ≈ " << pi << std::endl;
    	    return 0;
    	}
    	```
    
    
    
    

2. 协程 (Coroutines)

  • 目标: 简化异步编程、惰性生成器、状态机等的实现。
  • 核心: 提供一种可以挂起(co_await)和恢复执行的函数。函数状态(局部变量、执行位置)在挂起时自动保存。
  • 关键字: co_await, co_yield, co_return。函数体中使用这些关键字即成为协程。
  • 底层: 依赖编译器生成的“协程框架”代码(承诺对象promise_type、协程句柄coroutine_handle)。
  • 库支持: std::generator(C++23), std::task(提案中),或使用第三方库(如 cppcoro)。
  • 常用/常考: 实现异步 I/O、生成器序列、复杂状态机。是面试高级 C++ 岗位的热点话题,常考基本概念和使用场景。
  • 示例
    #include <coroutine>
    #include <iostream>
    #include <memory>
    
    // 生成器协程示例
    template<typename T>
    struct Generator {
        struct promise_type {
            T current_value;
            auto get_return_object() { return Generator{this}; }
            auto initial_suspend() { return std::suspend_always{}; }
            auto final_suspend() noexcept { return std::suspend_always{}; }
            void return_void() {}
            void unhandled_exception() { std::terminate(); }
            auto yield_value(T value) {
                current_value = value;
                return std::suspend_always{};
            }
        };
    
        using Handle = std::coroutine_handle<promise_type>;
        Handle coro_handle;
    
        explicit Generator(promise_type* p) : coro_handle(Handle::from_promise(*p)) {}
        ~Generator() { if (coro_handle) coro_handle.destroy(); }
    
        T next() {
            coro_handle.resume();
            return coro_handle.promise().current_value;
        }
    };
    
    Generator<int> range(int start, int end) {
        for (int i = start; i <= end; ++i) {
            co_yield i;  // 挂起并返回值
        }
    }
    
    int main() {
        auto gen = range(1, 5);
        while (true) {
            int val = gen.next();
            std::cout << val << " ";
            if (val >= 5) break;
        }
        return 0;
    }
    

3. 概念 (Concepts)

  • 目标: 大幅改进模板元编程,为模板参数提供编译时类型约束,使错误信息更清晰,代码可读性更高。
  • 核心: 定义一组对类型的要求(约束)。
  • 关键字: concept, requires
  • 用法:
    • 定义概念:
      template <typename T>
      concept Integral = std::is_integral_v<T>; // 使用类型特性
      template <typename T>
      concept Addable = requires(T a, T b) {
          { a + b } -> std::convertible_to<T>; // 要求表达式有效且结果可转换
      };
      
    • 约束模板参数:
      template <Integral T> // 语法糖
      T add(T a, T b) { return a + b; }
      template <typename T> requires Addable<T> // requires 子句
      T add(T a, T b) { return a + b; }
      
    • 约束 auto:
      Addable auto add(Addable auto a, Addable auto b) { return a + b; }
      
    • 示例
      #include <concepts>
      #include <vector>
      #include <iostream>
      
      // 定义概念
      template<typename T>
      concept Addable = requires(T a, T b) {
          { a + b } -> std::convertible_to<T>;
      };
      
      // 约束模板函数
      template <Addable T>
      T sum(T a, T b) {
          return a + b;
      }
      
      // 约束 auto
      Addable auto add(Addable auto a, Addable auto b) {
          return a + b;
      }
      
      int main() {
          std::cout << sum(3, 4) << std::endl;      // 正确:int 满足 Addable
          std::cout << add(2.5, 3.7) << std::endl;  // 正确:double 满足 Addable
          // sum("a", "b");                         // 错误:const char* 不满足 Addable
          return 0;
      }
      
  • 标准概念库: <concepts> 头文件提供了大量预定义概念(std::integral, std::copyable, std::invocable 等)。
  • 常用/常考: 现代模板编程的基石,极大提升泛型代码的健壮性和可读性。必考内容,常要求编写或理解概念约束的模板。

4. 三向比较 (Spaceship Operator, <=>)

  • 目标: 简化用户自定义类型的比较运算符定义。
  • 核心: 引入新的运算符 <=> (spaceship),它在一个操作中返回两个值的所有可能比较关系(小于、等于、大于)。
  • 返回值类型: std::strong_ordering, std::weak_ordering, std::partial_ordering(定义在 <compare> 中)。
  • 编译器自动生成: 如果类定义了默认的 operator<=>,编译器会自动生成 ==, !=, <, <=, >, >= 六个运算符(除非显式定义或删除)。
    struct Point {
        int x, y;
        auto operator<=>(const Point&) const = default; // 按成员声明顺序进行字典序比较
    };
    
  • 示例
    #include <compare>
    #include <iostream>
    
    struct Point {
        int x, y;
        auto operator<=>(const Point&) const = default;  // 默认比较(按成员字典序)
    };
    
    int main() {
        Point p1{1, 2}, p2{1, 3};
        std::cout << (p1 < p2) << std::endl;   // true
        std::cout << (p1 == p2) << std::endl;  // false
        return 0;
    }
    
  • 常用/常考: 极大简化了需要全序或偏序类型的代码编写,是重载运算符相关问题的重点。

5. 指定初始化 (Designated Initializers)

  • 目标: 提高聚合类型初始化的清晰度和安全性(类似 C 的指定初始化,但有更严格的 C++ 规则)。
  • 核心: 允许在初始化聚合类型(数组、结构体、类 - 如果满足聚合初始化条件)时,显式指定成员名。
  • 规则:
    • 初始化器必须按类中成员的声明顺序出现(C 不要求,C++ 要求)。
    • 不能混合使用指定初始化器和非指定初始化器。
    • 不能嵌套指定初始化器(不能用于初始化非聚合子成员)。
    • 未显式指定的成员进行值初始化。
  • 示例:
    struct S { int a; double b; const char* c; };
    S s1 = { .a = 1, .b = 2.2, .c = "hello" }; // 正确
    S s2 = { .b = 3.3, .a = 2 }; // 错误!顺序必须与声明一致 (a 在 b 前)
    
  • 常用: 提高初始化复杂结构体时代码的可读性和防错能力。

6. constexpr 的增强

  • 目标: 让更多代码能在编译期执行。
  • 核心允许:
    • constexpr 虚函数: 虚函数现在可以是 constexpr
    • constexpr 动态内存分配 (new/delete):constexpr 函数内部可以使用 newdelete(分配的内存必须在编译期释放)。
    • constexpr try/catch:constexpr 函数中允许 try-catch 块(但 throwconstexpr 求值中仍不允许)。
    • constexpr 标准库的更多内容: 大量标准库容器和算法被标记为 constexpr(如 std::vector, std::string, std::sort 等)。
  • 常用/影响: 极大地扩展了编译时计算的可能性,使得更复杂的逻辑和数据结构可以在编译期构造和操作。

7. 立即函数 (consteval)

  • 目标: 确保函数一定在编译期被求值。
  • 核心:consteval 关键字声明的函数(称为“立即函数”)。如果调用它的上下文不能在编译期求值,则编译错误。
  • constexpr 区别: constexpr 函数可以在编译期或运行期求值;consteval 函数必须在编译期求值。
  • 常用: 用于强制编译期计算,保证某些关键操作(如某些元编程、字面量处理)没有运行时开销。

8. using 枚举 (Using-enum Declaration)

  • 目标: 简化作用域枚举(enum class)成员的访问。
  • 核心: 将枚举类的所有成员引入当前作用域。
  • 示例:
    enum class Color { Red, Green, Blue };
    void paint(Color c) {
        using enum Color; // 引入 Red, Green, Blue 到 paint 函数作用域
        switch (c) {
            case Red: ...   // 不需要 Color::Red
            case Green: ...
            case Blue: ...
        }
    }
    
  • 常用: 减少作用域枚举使用时重复写枚举类名的冗余。

📚 二、标准库特性

1. 范围库 (Ranges Library)

  • 目标: 提供处理元素序列(范围)的现代、可组合、惰性求值的算法和视图。
  • 核心组件:
    • 范围概念: 定义序列的要求(如 std::ranges::range, std::ranges::view)。
    • 范围算法:<algorithm> 头文件下有对应的 std::ranges:: 版本(如 std::ranges::sort, std::ranges::find)。接受范围对象,而非迭代器对。
    • 视图 (Views): 惰性求值的适配器,通过管道操作符 | 进行组合,不修改底层数据。
      • 常用视图: std::views::filter, std::views::transform, std::views::take, std::views::drop, std::views::reverse, std::views::join 等。
      • 示例:
        std::vector<int> vec = {1, 2, 3, 4, 5};
        auto result = vec
            | std::views::filter([](int i) { return i % 2 == 0; }) // 取偶数 [2, 4]
            | std::views::transform([](int i) { return i * i; });   // 平方 [4, 16]
        for (auto i : result) { ... } // 惰性求值,实际计算发生在迭代时
        
    • 范围工厂: std::views::iota (生成整数序列)。
  • 优点: 代码更简洁、可读性更高(类似函数式编程)、惰性求值提升性能(避免中间临时容器)、安全(范围自动管理边界)。
  • 常用/常考: 现代 C++ 数据处理的核心库,是替代传统迭代器+算法风格的主力。面试高频考点,常考视图组合和管道操作。
  • 示例
    		#include <ranges>
    		#include <vector>
    		#include <iostream>
    		#include <algorithm>
    		
    		int main() {
    		    std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6};
    		
    		    // 视图:过滤偶数并平方
    		    auto result = vec 
    		        | std::views::filter([](int x) { return x % 2 == 0; })
    		        | std::views::transform([](int x) { return x * x; });
    		
    		    for (int v : result) {
    		        std::cout << v << " ";  // 输出:4 16 36
    		    }
    		
    		    // 范围排序
    		    std::ranges::sort(vec);
    		    return 0;
    		}
    		```
    
    
    

2. 格式化库 (std::format)

  • 目标: 提供类型安全、可扩展、高性能的文本格式化机制,替代 printf 和复杂的 iostreams 拼接。
  • 核心: std::format(format_string, args...) 函数和 std::formatter 自定义格式化。
  • 语法: 类似 Python 的 str.format(),使用 {} 作为占位符。
  • 示例:
    #include <format>
    #include <iostream>
    int main() {
        std::string name = "World";
        int answer = 42;
        std::string message = std::format("Hello, {}! The answer is {}.", name, answer);
        std::cout << message << std::endl; // 输出: Hello, World! The answer is 42.
        // 直接输出到流
        std::cout << std::format("π ≈ {:.2f}", 3.1415926535) << std::endl; // 输出: π ≈ 3.14
    }
    
  • 优点: 类型安全、位置和命名参数支持、良好的本地化支持、性能通常优于 iostreamssprintf
  • 常用: 快速成为新的标准输出和字符串构建方式,广泛使用。

3. std::span

  • 目标: 提供对连续内存序列(如数组、std::vector, std::array)的非拥有视图(引用),避免传递指针+大小的原始组合。
  • 核心: 轻量级,包含指向数据的指针和大小(或范围)。
  • 特点: 非拥有、不分配内存、可读写(除非 const 限定)。
  • 用途: 安全地传递数组或容器的一部分给函数,作为函数参数或返回值。
  • 示例:
    #include <span>
    #include <vector>
    void process_chunk(std::span<int> data) {
        for (auto& elem : data) {
            elem *= 2; // 修改原始数据
        }
    }
    int main() {
        std::vector<int> vec = {1, 2, 3, 4, 5};
        process_chunk({vec.data() + 1, 3}); // 处理 vec[1] 到 vec[3] (2, 3, 4)
        // vec 变为 {1, 4, 6, 8, 5}
    }
    
  • 常用/常考: 提高处理连续序列的 API 安全性和表达力,是现代 C++ API 设计的推荐做法。常考其与原始指针/数组的区别和优点。

4. std::jthread

  • 目标: 提供更安全、更方便的线程管理,解决 std::thread 在析构时行为(需要显式 joindetach)可能导致的资源泄漏或崩溃问题。
  • 核心: “Joining Thread”。在析构函数中,如果线程仍可连接(joinable),它会自动调用 join()。这意味着在大多数情况下,你不需要手动 join
  • 协作取消: 支持通过 std::stop_tokenstd::stop_source 机制请求线程停止(协作式)。
  • 示例:
    #include <thread>
    #include <iostream>
    void worker(std::stop_token stopToken) {
        while (!stopToken.stop_requested()) {
            std::cout << "Working...\n";
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
        std::cout << "Stopped by request.\n";
    }
    int main() {
        {
            std::jthread jt(worker); // 创建并启动线程
            std::this_thread::sleep_for(std::chrono::seconds(3));
        } // jt 析构时自动调用 join(),并通过 stop_source 请求停止
        return 0;
    }
    
  • 常用: 推荐用于所有新代码中的线程管理,比 std::thread 更安全。

5. 日历和时区扩展 (<chrono>)

  • 目标: 提供强大的日历日期和时区处理能力。
  • 核心类型:
    • 日历类型: std::chrono::year, std::chrono::month, std::chrono::day, std::chrono::year_month_day, std::chrono::weekday, std::chrono::month_day 等。
    • 时区支持: std::chrono::time_zone, std::chrono::zoned_time
    • 格式化和解析:std::format 集成。
  • 示例:
    #include <chrono>
    #include <format>
    #include <iostream>
    using namespace std::chrono;
    int main() {
        auto today = floor<days>(system_clock::now()); // 当前 UTC 日期
        year_month_day ymd{today}; // 转换为年-月-日结构
        std::cout << std::format("Today is {:%Y-%m-%d}\n", ymd); // 输出格式化的日期
        // 处理时区
        zoned_time zt{"America/New_York", system_clock::now()};
        std::cout << std::format("Current time in New York: {:%T %Z}\n", zt);
    }
    
  • 常用: 处理日期和时间相关逻辑变得非常方便和强大。

🎯 总结重点 (常考常用)

  • 模块 (Modules): 未来构建方式,解决头文件痛点。
  • 概念 (Concepts): 模板编程革命,提升泛型代码质量。
  • 范围库 (Ranges + Views): 现代数据处理范式,简洁高效安全。
  • 协程 (Coroutines): 异步编程/生成器新模式 (理解概念和基本应用)。
  • 三向比较 (<=>) 和默认比较: 极大简化比较运算符定义。
  • std::format: 新的格式化标准,类型安全易用。
  • std::span: 安全传递连续序列的视图。
  • std::jthread: 更安全的线程管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值