C++20:革命性更新

C++20 是继 C++11 之后最大的更新,引入了模块、协程、概念和 ranges 等重大特性。

Concepts(概念)

#include <concepts>

// 定义概念
template<typename T>
concept Integral = std::is_integral_v<T>;

template<typename T>
concept Addable = requires(T a, T b) {
    a + b;  // 必须支持 + 运算
};

// 使用概念约束模板
template<Integral T>
T add(T a, T b) {
    return a + b;
}

// requires 子句
template<typename T>
requires Addable<T>
T multiply(T a, T b) {
    return a * b;
}

// 简写语法
auto subtract = [](std::integral auto a, std::integral auto b) {
    return a - b;
};

// 标准概念
template<std::sortable T>
void sortContainer(std::vector<T>& vec) {
    std::sort(vec.begin(), vec.end());
}

Ranges(范围库)

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

std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 过滤偶数
auto evens = vec | std::views::filter([](int x) { return x % 2 == 0; });

// 转换
auto squared = evens | std::views::transform([](int x) { return x * x; });

// 取前 3 个
auto result = squared | std::views::take(3);

// 链式调用
auto final = vec
    | std::views::filter([](int x) { return x % 2 == 0; })
    | std::views::transform([](int x) { return x * x; })
    | std::views::take(3);

// 使用
for (auto x : final) {
    std::cout << x << " ";  // 4 16 36
}

// 直接创建视图
auto view = std::views::iota(1, 10) | std::views::filter([](int x) { return x % 2; });

协程(Coroutines)

#include <coroutine>
#include <iostream>

// 简单的生成器
template<typename T>
struct Generator {
    struct promise_type {
        T 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 val) {
            value = val;
            return {};
        }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };

    std::coroutine_handle<promise_type> h;
    Generator(std::coroutine_handle<promise_type> handle) : h(handle) {}
    ~Generator() { if (h) h.destroy(); }

    bool next() {
        h.resume();
        return !h.done();
    }

    T value() { return h.promise().value; }
};

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

// 使用
auto gen = range(1, 5);
while (gen.next()) {
    std::cout << gen.value() << " ";  // 1 2 3 4
}

模块(Modules)

// math.ixx (模块接口)
export module math;

export int add(int a, int b) {
    return a + b;
}

export int multiply(int a, int b) {
    return a * b;
}

// main.cpp
import math;
import <iostream>;

int main() {
    std::cout << add(2, 3) << "\n";  // 5
    return 0;
}

三路比较运算符(<=>)

#include <compare>

struct Point {
    int x;
    int y;

    // 自动生成所有比较运算符
    auto operator<=>(const Point&) const = default;
};

Point p1{1, 2};
Point p2{1, 3};

if (p1 < p2) { /* ... */ }
if (p1 == p2) { /* ... */ }
if (p1 != p2) { /* ... */ }

// 自定义比较
struct Version {
    int major;
    int minor;
    int 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;
    }
};

Designated Initializers(指定初始化器)

struct Point {
    int x;
    int y;
    int z;
};

Point p{.x = 1, .z = 3};  // y 初始化为 0

// 数组
int arr[5] = {[1] = 10, [3] = 30};  // {0, 10, 0, 30, 0}

// 结构体数组
Point points[] = {{.x = 1}, {.y = 2}, {.z = 3}};

consteval 和 constinit

// consteval:必须在编译期求值
consteval int square(int x) {
    return x * x;
}

constexpr int result = square(5);  // OK
// int x = 5;
// int y = square(x);  // 编译错误,x 不是常量

// constinit:必须在编译期初始化
constinit int global = 42;

// 结合使用
consteval int compute(int x) { return x * 2; }
constinit int computed = compute(42);

范围 for 循环支持初始化器

std::vector<int> vec = {1, 2, 3, 4, 5};

// C++20 之前
for (auto& elem : vec) {
    elem *= 2;
}

// C++20:在循环中声明变量
for (auto vecCopy = vec; auto& elem : vecCopy) {
    // 使用 vecCopy
    elem *= 2;
}

// 更复杂的用法
for (auto it = vec.begin(), end = vec.end(); auto& elem : vec) {
    // 使用 it 和 end
}

Lambda 模板参数列表

// C++20 之前
auto lambda1 = [](auto x) { return x * 2; };

// C++20:显式模板参数
auto lambda2 = []<typename T>(T x) { return x * 2; };

// 多个模板参数
auto lambda3 = []<typename T, typename U>(T a, U b) {
    return a + b;
};

// 模板参数默认值
auto lambda4 = []<typename T = int>(T x) { return x; };

// 在 requires 子句中使用
auto lambda5 = []<typename T>(T x) requires std::integral<T> {
    return x * 2;
};

[[no_unique_address]] 属性

struct Empty {};

struct A {
    int x;
    Empty e;  // 不占用空间
};

struct B {
    int x;
    [[no_unique_address]] Empty e;  // 编译器可以优化,不占用额外空间
};

// 编译器可能将 B 的大小优化为与 int 相同
static_assert(sizeof(B) == sizeof(int));

[[likely]] 和 [[unlikely]] 属性

int process(int value) {
    switch (value) {
        [[likely]] case 1:
            return 10;
        [[unlikely]] case 2:
            return 20;
        default:
            return 0;
    }
}

bool check(int x) {
    if (x > 0) [[likely]] {
        return true;
    }
    return false;
}

void logMessage(int level) {
    if (level > 100) [[unlikely]] {
        // 警告:这很少见
    }
}

std::format

#include <format>

std::string name = "Alice";
int age = 30;

// 类似 Python 的格式化
std::string s1 = std::format("Name: {}, Age: {}", name, age);

// 带索引
std::string s2 = std::format("{1} is {0} years old", age, name);

// 格式化选项
std::string s3 = std::format("Pi: {:.2f}", 3.14159);  // Pi: 3.14
std::string s4 = std::format("Hex: {:#x}", 255);      // Hex: 0xff
std::string s5 = std::format("Padding: {:>10}", "test");  // Padding:      test
std::string s6 = std::format("Zeros: {:0>5}", 42);    // Zeros: 00042

std::span

#include <span>

void processArray(std::span<int> arr) {
    for (auto x : arr) {
        std::cout << x << " ";
    }
}

int arr[] = {1, 2, 3, 4, 5};
std::vector<int> vec = {1, 2, 3, 4, 5};

processArray(arr);   // OK
processArray(vec);   // OK

// 子视图
std::span<int> sub(arr, 3);  // 前 3 个元素

// 动态大小
std::span<int> dynamic(vec.data(), vec.size());

std::source_location

#include <source_location>

void log(const std::string& msg,
         std::source_location loc = std::source_location::current()) {
    std::cout << loc.file_name() << ":" << loc.line() << " "
              << loc.function_name() << ": " << msg << "\n";
}

void foo() {
    log("Hello");  // 自动记录调用位置
}

std::bit_cast

#include <bit>

// 类型重新解释
float f = 3.14f;
uint32_t bits = std::bit_cast<uint32_t>(f);

// 位反转
struct Packed {
    uint32_t x : 10;
    uint32_t y : 10;
    uint32_t z : 10;
};

uint32_t raw = 0xABCDEF;
Packed p = std::bit_cast<Packed>(raw);

std::endian

#include <bit>

// 检查字节序
if (std::endian::native == std::endian::little) {
    // 小端字节序
}

// 字节序转换
uint32_t x = 0x12345678;
uint32_t swapped = std::byteswap(x);

std::make_shared 支持数组

// C++20 之前
auto arr = std::make_shared<std::vector<int>>(10, 0);

// C++20 支持数组
auto arr2 = std::make_shared<int[]>(10);
arr2[0] = 1;
arr2[1] = 2;

// 多维数组
auto matrix = std::make_shared<int[][3]>(5);

contains 成员函数

std::set<int> s = {1, 2, 3, 4, 5};

// C++20 之前
if (s.find(3) != s.end()) { /* ... */ }

// C++20
if (s.contains(3)) { /* ... */ }

// 同样适用于 map, unordered_map, unordered_set
std::map<std::string, int> m{{"a", 1}, {"b", 2}};
if (m.contains("a")) { /* ... */ }

starts_with 和 ends_with

std::string str = "Hello, World!";

if (str.starts_with("Hello")) { /* ... */ }
if (str.ends_with("!")) { /* ... */ }

// 同样适用于 string_view
std::string_view sv = "test.txt";
if (sv.ends_with(".txt")) { /* ... */ }

// C++23 也添加到了 std::string::contains

std::jthread

#include <thread>

std::jthread jt([](std::stop_token st) {
    while (!st.stop_requested()) {
        // 执行任务
    }
});

// 析构时自动 join
// 或者显式请求停止
jt.request_stop();

std::stop_token

#include <thread>

void worker(std::stop_token st, int id) {
    while (!st.stop_requested()) {
        // 工作
        std::this_thread::sleep_for(100ms);
    }
}

std::jthread t1(worker, 1);
std::jthread t2(worker, 2);

// 请求停止
t1.request_stop();
t2.request_stop();

// 所有 jthread 析构时自动 join

信号量(Semaphores)

#include <semaphore>

std::counting_semaphore<5> sem(5);  // 最多 5 个许可

void worker() {
    sem.acquire();  // 获取许可
    // 临界区
    sem.release();  // 释放许可
}

// 二进制信号量
std::binary_semaphore bs(1);
std::binary_semaphore bs2(0);  // 初始为 0

Barriers

#include <barrier>

auto phase1 = [] { /* 第一阶段工作 */ };
auto phase2 = [] { /* 第二阶段工作 */ };

std::barrier barrier(2, [] { /* 阶段完成回调 */ });

std::thread t1([&] {
    phase1();
    barrier.arrive_and_wait();  // 等待 t2
    phase2();
});

std::thread t2([&] {
    phase1();
    barrier.arrive_and_wait();  // 等待 t1
    phase2();
});

Latches

#include <latch>

std::latch workDone(3);  // 3 个工作线程

void worker(int id) {
    // 做工作
    workDone.count_down();  // 标记完成
}

void master() {
    // 等待所有工作完成
    workDone.wait();

    // 继续
}

Atomic wait/notify

#include <atomic>

std::atomic<int> counter{0};

// 等待直到值改变
int oldValue = counter.load();
while (counter.wait(oldValue) == oldValue) {
    // 值未改变,继续等待
}

// 通知所有等待的线程
counter.store(1);
counter.notify_all();

std::atomic<std::shared_ptr>

#include <atomic>
#include <memory>

struct Node {
    int value;
    std::atomic<std::shared_ptr<Node>> next;
};

std::atomic<std::shared_ptr<Node>> head;

// 原子地读取
std::shared_ptr<Node> current = head.load();

// 原子地 CAS
std::shared_ptr<Node> newNode = std::make_shared<Node>();
std::shared_ptr<Node> expected = head.load();
do {
    newNode->next = expected;
} while (!head.compare_exchange_weak(expected, newNode));

常用特性总结

最常用的 C++20 特性:

  • Concepts(概念)
  • Ranges(范围库)
  • 三路比较运算符(<=>
  • std::format
  • std::span
  • contains 成员函数
  • starts_with / ends_with
  • std::jthread