C++20 - 革命性更新
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: 00042std::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::containsstd::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); // 初始为 0Barriers
#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::formatstd::spancontains成员函数starts_with/ends_withstd::jthread








