C++20 核心特性速览
定义与作用
C++20 是 C++ 史上最大的更新之一,引入了四大核心特性:Concepts(概念)、Ranges(范围库)、Coroutines(协程)和 Modules(模块),以及三路比较运算符 <=>、std::span 和 std::format 等实用改进。
核心原理
C++20 四大支柱
完整示例
示例一:Concepts 约束矩阵运算
场景说明:白歌用 Concepts 约束飞翔科技数学库的模板参数。
#include <iostream>
#include <concepts>
#include <vector>
#include <type_traits>
// 定义 Concept:只接受数值类型
template<typename T>
concept Numeric = std::is_arithmetic_v<T>;
// 受约束的矩阵类
template<Numeric T>
class Matrix {
public:
Matrix(size_t rows, size_t cols)
: rows_(rows), cols_(cols), data_(rows * cols) {}
T& at(size_t r, size_t c) { return data_[r * cols_ + c]; }
const T& at(size_t r, size_t c) const { return data_[r * cols_ + c]; }
// Concepts 直接写在参数上
void fill(Numeric auto val) {
std::fill(data_.begin(), data_.end(), val);
}
size_t rows() const { return rows_; }
size_t cols() const { return cols_; }
void print(const char* name) const {
std::cout << name << " (" << rows_ << "x" << cols_ << "):\n";
for (size_t i = 0; i < rows_; ++i) {
std::cout << " ";
for (size_t j = 0; j < cols_; ++j)
std::cout << at(i, j) << " ";
std::cout << "\n";
}
}
private:
size_t rows_, cols_;
std::vector<T> data_;
};
// 仅对 Numeric 类型生效
template<Numeric T>
Matrix<T> addMatrices(const Matrix<T>& a, const Matrix<T>& b) {
Matrix<T> result(a.rows(), a.cols());
for (size_t i = 0; i < a.rows(); ++i)
for (size_t j = 0; j < a.cols(); ++j)
result.at(i, j) = a.at(i, j) + b.at(i, j);
return result;
}
// 三路比较运算符:自动生成 ==, !=, <, <=, >, >=
struct ServerLoad {
double cpu;
double memory;
int activeConnections;
auto operator<=>(const ServerLoad&) const = default;
};
int main() {
std::cout << "=== 飞翔科技 C++20 特性展示 ===\n\n";
// 1. Concepts
Matrix<int> a(2, 3);
a.fill(1);
a.at(0, 1) = 3;
Matrix<int> b(2, 3);
b.fill(2);
b.at(1, 2) = 5;
a.print("矩阵 A");
b.print("矩阵 B");
auto c = addMatrices(a, b);
c.print("A + B");
// 以下将编译失败(Concept 约束)
// Matrix<std::string> strMat(2, 2); // ❌ 不满足 Numeric concept
// 2. 三路比较 <=>
std::cout << "\n--- 三路比较 ---\n";
ServerLoad s1{75.0, 60.0, 1000};
ServerLoad s2{80.0, 55.0, 1200};
ServerLoad s3{75.0, 60.0, 1000};
std::cout << std::boolalpha;
std::cout << "s1 == s3: " << (s1 == s3) << "\n";
std::cout << "s1 != s2: " << (s1 != s2) << "\n";
std::cout << "s1 < s2: " << (s1 < s2) << "\n";
std::cout << "s2 > s1: " << (s2 > s1) << "\n";
// <=> 比较规则:先 cpu,再 memory,最后 activeConnections
// 3. span:安全数组视图
std::cout << "\n--- span 安全视图 ---\n";
std::vector<int> loads{10, 25, 50, 75, 90, 55, 30};
auto printSpan = [](std::span<const int> s, const char* label) {
std::cout << label << ": ";
for (auto v : s) std::cout << v << " ";
std::cout << " (size=" << s.size() << ")\n";
};
printSpan(loads, "完整视图");
std::span<int> mid = std::span(loads).subspan(2, 3);
mid[0] = 99; // 修改视图即修改原数据
printSpan(loads, "修改后 ");
// 4. Ranges 管道式操作
std::cout << "\n--- Ranges 管道 ---\n";
std::vector<int> data{5, 12, 3, 8, 15, 7, 20, 1, 9};
auto evenSquares = data
| 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 (auto v : evenSquares) std::cout << v << " ";
std::cout << "\n";
// Ranges 排序
std::ranges::sort(data);
std::cout << "排序后: ";
for (auto v : data) std::cout << v << " ";
std::cout << "\n";
}
预期输出:
=== 飞翔科技 C++20 特性展示 ===
矩阵 A (2x3):
1 3 1
1 1 1
矩阵 B (2x3):
2 2 2
2 2 5
A + B (2x3):
3 5 3
3 3 6
--- 三路比较 ---
s1 == s3: true
s1 != s2: true
s1 < s2: true
s2 > s1: true
--- span 安全视图 ---
完整视图: 10 25 50 75 90 55 30 (size=7)
修改后 : 10 25 99 75 90 55 30 (size=7)
--- Ranges 管道 ---
偶数平方 (前3个): 144 64 400
排序后: 1 3 5 7 8 9 12 15 20
逐段分析:
- Concept
Numeric约束模板参数,错误信息清晰 = default的<=>自动生成全部六种比较运算符span是轻量级数组视图,不拥有数据,带边界检查- Ranges 的
|管道语法替代嵌套函数调用,延迟求值
示例二:format 替换 iostream
场景说明:黄俪用 std::format 重构飞翔科技日志输出。
#include <iostream>
#include <format>
#include <string>
#include <chrono>
#include <vector>
struct ApiMetric {
std::string endpoint;
int statusCode;
double latencyMs;
size_t bytesTransferred;
};
int main() {
std::cout << "=== 飞翔科技格式化日志 (C++20 format) ===\n\n";
// format 替代 ostringstream
std::string title = std::format("=== {} v{}.{}.{} ===",
"飞翔-API-Gateway", 2, 1, 0);
std::cout << title << "\n\n";
// 精确控制格式
double hitRate = 95.237;
std::cout << std::format("缓存命中率: {:.2f}%\n", hitRate); // 保留2位
std::cout << std::format("十六进制: {:#x}\n", 255); // 0xff
std::cout << std::format("前导零: {:08d}\n", 42); // 00000042
// 表格对齐
std::cout << "\n";
std::cout << std::format("{:<20} {:>6} {:>10} {:>12}\n",
"接口", "状态", "延迟(ms)", "传输字节");
std::cout << std::string(52, '-') << "\n";
std::vector<ApiMetric> metrics{
{"/api/v1/users", 200, 12.5, 1024},
{"/api/v1/orders", 200, 45.8, 8192},
{"/api/v1/products", 500, 0.0, 0},
};
for (const auto& m : metrics) {
std::cout << std::format("{:<20} {:>6} {:>10.1f} {:>12}\n",
m.endpoint, m.statusCode, m.latencyMs, m.bytesTransferred);
}
// 编译期 format 检查(C++20 编译期字符串)
// std::format("{:d}", "oops"); // ❌ 编译错误!类型不匹配
}
预期输出:
=== 飞翔科技格式化日志 (C++20 format) ===
=== 飞翔-API-Gateway v2.1.0 ===
缓存命中率: 95.24%
十六进制: 0xff
前导零: 00000042
接口 状态 延迟(ms) 传输字节
----------------------------------------------------
/api/v1/users 200 12.5 1024
/api/v1/orders 200 45.8 8192
/api/v1/products 500 0.0 0
逐段分析:
std::format类型安全,格式串与参数不匹配时编译报错- 类似 Python 的
str.format语法,{}占位 {:.2f}控制精度,{:<20}左对齐,{:>6}右对齐- 比
iostream更简洁,无需setw/setprecision等 manipulator
易错场景与面试考点
易错场景
1. span 不拥有数据
std::span<int> makeSpan() {
std::vector<int> v{1, 2, 3};
return std::span(v); // ❌ v 析构后 span 悬挂
}
2. Ranges 视图是惰性的
auto v = data | std::views::filter(pred);
// 实际过滤在遍历时才执行
// 修改源数据后再遍历,看到的是最新数据
3. <=> 不等于 ==
// operator<=> 不自动生成 operator==(C++20 行为)
// 需要显式 default 或单独定义
// [注:此细节在不同实现中可能有差异]
面试考点
| 特性 | 要点 |
|---|---|
| Concepts | template<Concept T> 约束模板,比 SFINAE 清晰 |
| requires 子句 | requires std::integral<T> 细粒度约束 |
| Ranges | std::views::filter/transform/take 管道式延迟求值 |
| 协程 | co_await/co_yield/co_return,编译器生成状态机 |
| <=> | 三路比较,= default 自动生成全部比较运算符 |
| span | 非拥有型数组视图,subspan/first/last |
| format | 类型安全格式化,编译期检查 |
| Modules | import std; 替代 #include,减少编译时间 |