文章目录
- C++20 vs C++17:新特性对比与用法指南
-
- 一、模板约束:Concepts
- 二、数据处理:Ranges
- 三、协程:Coroutines
- 四、模块:Modules
- 五、比较运算符:`<=> ` 飞船操作符
- 六、格式化:std::format
- 七、连续内存视图:std::span
- 八、线程:std::jthread
- 九、编译期增强:consteval / constinit
- 十、其他好用的小特性
-
- 指定初始化器(Designated Initializers)
- std::source_location:替代 `__FILE__` / `__LINE__`
- 位操作工具 <bit>
- 容器增强
- 日历与时区(<chrono> 大扩展)
- 十一、特性分层采用建议
- 十二、一句话记忆
C++20 vs C++17:新特性对比与用法指南
C++20 是继 C++11 之后最大的一次升级,核心是四大支柱:Concepts、Ranges、Coroutines、Modules。下面继续用「C++17 怎么写 → C++20 怎么写」的对比方式,把每个特性的用法、收益和坑都讲清楚。
一、模板约束:Concepts
C++17:靠 static_assert + 类型萃取,报错信息像天书 C++20:把“类型必须满足什么”写成代码本身
// C++17 — SFINAE / static_assert
template <typename T>
T add(T a, T b) {
static_assert(std::is_arithmetic_v<T>, "T must be arithmetic");
return a + b;
}
// 传错类型时:报错在函数体深处,几百行模板回溯
// C++20 — Concepts
template <typename T>
concept Number = std::integral<T> || std::floating_point<T>;
template <Number T>
T add(T a, T b) {
return a + b;
}
// 或更简洁的缩写语法
auto add(Number auto a, Number auto b) { return a + b; }
传错类型时,编译器直接说“Number 约束未满足”,而不是吐一屏模板展开。
自定义 concept:
template <typename T>
concept Container = requires(T t) {
t.begin();
t.end();
typename T::value_type;
};
二、数据处理:Ranges
C++17:算法要传迭代器对,组合多个操作要中间容器 C++20:算法直接作用于范围,用 | 管道组合,视图惰性求值
std::vector<int> nums = {1,2,3,4,5,6,7,8,9};
// C++17 — 多步、要临时容器
std::vector<int> evens;
std::copy_if(nums.begin(), nums.end(),
std::back_inserter(evens),
int n{ return n % 2 == 0; });
std::vector<int> squared;
std::transform(evens.begin(), evens.end(),
std::back_inserter(squared),
int n{ return n * n; });
// C++20 — 一条管道,零中间拷贝
auto view = nums
| std::views::filter(int n{ return n % 2 == 0; })
| std::views::transform(int n{ return n * n; });
for (int x : view) std::cout << x << " "; // 4 16 36 64 81…
要点:
- 视图不拥有数据,只在遍历时计算
- 想落盘成容器:std::vector<int> result(view.begin(), view.end());(std::ranges::to 是 C++23)
排序也更简洁:
// C++17
std::sort(v.begin(), v.end());
// C++20
std::ranges::sort(v);
std::ranges::sort(v, std::greater{}, &Person::age); // 直接按成员排序
三、协程:Coroutines
C++17:异步/惰性序列只能靠回调、状态机、手写迭代器 C++20:co_await / co_yield / co_return 让函数能暂停和恢复
// C++17 — 生成斐波那契要手写迭代器或闭包状态
struct Fib {
int a = 0, b = 1;
int operator()() {
int next = a;
a = b; b = next + b;
return next;
}
};
// C++20 — 协程生成器(需要自己定义 promise_type 或用库)
#include <coroutine>
template <typename T>
struct Generator {
struct promise_type {
T current;
auto yield_value(T v) { current = v; return std::suspend_always{}; }
auto get_return_object() { return Generator{this}; }
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() { std::terminate(); }
};
// … 迭代器封装省略
};
Generator<int> fibonacci() {
int a = 0, b = 1;
while (true) {
co_yield a;
auto next = a + b;
a = b; b = next;
}
}
for (int x : fibonacci()) {
if (x > 100) break;
std::cout << x << " ";
}
⚠️ 重要边界:C++20 只给了协程的底层机制,标准库没有提供现成的 task / generator 类型(那些是 C++23 的 std::generator,或部分第三方库如 cppcoro)。生产里别裸写 promise_type,用封装好的库。
四、模块:Modules
C++17:靠 #include 文本替换,重复解析、宏泄漏、编译慢 C++20:import 替代 #include,显式导出,编译一次复用
// C++17 — math.h
#ifndef MATH_H
#define MATH_H
inline int add(int a, int b) { return a + b; }
#endif
// C++20 — math.cppm
export module math;
export int add(int a, int b) { return a + b; }
// 使用方
import math; // 不是 #include
int x = add(1, 2);
模块特点:
- 默认封闭,不导出的符号对外不可见
- 宏不会泄漏到导入方
- 编译速度更快(BMI 缓存)
⚠️ 模块对构建系统要求高:CMake 需 3.28+,GCC/Clang/MSVC 支持程度不一。老项目别一次性迁移,头文件和模块可长期共存。
五、比较运算符:<=> 飞船操作符
C++17:要手写 == != < > <= >= 六个运算符 C++20:一行 = default 自动合成全部
// C++17
struct Point {
int x, y;
bool operator==(const Point& o) const { return x==o.x && y==o.y; }
bool operator!=(const Point& o) const { return !(*this == o); }
bool operator< (const Point& o) const { return x<o.x || (x==o.x && y<o.y); }
// … 还有 > <= >=
};
// C++20
struct Point {
int x, y;
auto operator<=>(const Point&) const = default; // 全有了
};
需要自定义顺序时:
auto operator<=>(const Person& o) const {
return age <=> o.age; // 只按年龄比较,其余自动推导
}
六、格式化:std::format
C++17:printf 不安全,cout 拼接啰嗦 C++20:类型安全、编译期检查格式串
// C++17
printf("Hello %s, age %d\\n", name.c_str(), age);
std::cout << "Hello " << name << ", age " << age << "\\n";
// C++20
#include <format>
std::string s = std::format("Hello {}, age {}", name, age);
std::cout << s << "\\n";
注:std::print / std::println 是 C++23 才有的,C++20 只有 std::format。
七、连续内存视图:std::span
C++17:函数参数常用 T* + size_t 两参数,容易不一致 C++20:std::span 把“指针+长度”打包成一个安全视图
// C++17
void process(const uint8_t* data, size_t len);
// C++20
void process(std::span<const uint8_t> data) {
for (auto b : data) { /* … */ }
std::cout << data.size();
}
std::vector<uint8_t> v = {1,2,3};
uint8_t arr[3] = {1,2,3};
process(v); // OK
process(arr); // OK
process({v.data(), 2}); // 子区间也 OK
零开销、带边界检查(debug 模式)、不拥有内存。
八、线程:std::jthread
C++17:std::thread 忘了 join() 就直接 terminate C++20:析构自动 join,还支持协作式取消
// C++17
std::thread t({ /* 长时间工作 */ });
// 如果忘记 t.join(); 程序直接崩
// C++20
void worker(std::stop_token st) {
while (!st.stop_requested()) {
// 定期检查取消信号
}
}
std::jthread t(worker);
// 析构时自动请求停止 + 自动 join
t.request_stop();
配套的同步原语也补齐了:std::latch、std::barrier、std::counting_semaphore、std::stop_token。
九、编译期增强:consteval / constinit
C++17:constexpr 表示“可以在编译期算”,但不强制 C++20:consteval 强制编译期,constinit 保证静态初始化顺序
// C++17
constexpr int sq(int x) { return x * x; }
int a = sq(5); // 编译期
int b = sq(rand());// 也合法,运行期
// C++20
consteval int sq(int x) { return x * x; }
int a = sq(5); // OK
// int b = sq(rand()); // 编译错误:必须编译期可求
constinit static int global = 42; // 保证在静态初始化阶段完成,避免静态初始化顺序灾难
十、其他好用的小特性
指定初始化器(Designated Initializers)
// C++20
Config cfg{
.host = "localhost",
.port = 8080,
.timeout_ms = 3000,
};
// 字段顺序可乱、可缺省,比位置初始化安全得多
std::source_location:替代 __FILE__ / __LINE__
void log(std::string_view msg,
std::source_location loc = std::source_location::current()) {
std::cout << loc.file_name() << ":" << loc.line()
<< " " << msg << "\\n";
}
位操作工具
#include <bit>
int pop = std::popcount(0b1101); // 3
int z = std::countl_zero(8u); // 前导零个数
auto b = std::bit_cast<float>(0x3f800000); // 安全类型转换
容器增强
std::vector<int> v = {1,2,3,4,5};
// C++20 新增自由函数
std::erase(v, 3); // 删除所有等于3的元素
std::erase_if(v, int x{ return x % 2 == 0; });
if (v.contains(42)) { /* map 新增 contains(),比 count() 语义清晰 */ }
日历与时区( 大扩展)
using namespace std::chrono;
auto tp = sys_days{2026y/10/27} + 14h + 30min;
// 时区转换
auto zoned = zoned_time{"Asia/Shanghai", tp};
十一、特性分层采用建议
不是所有 C++20 特性都适合立刻上生产,按成熟度分三档:
| 立刻用 | Concepts、Ranges、<=>、std::format、std::span、jthread、consteval | 收益大、风险低 |
| 谨慎用 | 协程 | 标准库没给高层封装,需依赖 cppcoro / Asio 等 |
| 观望/试点 | Modules | 构建系统、IDE、第三方库生态还在跟上 |
编译器最低版本参考(2026 视角):
- GCC 10+(Concepts/Ranges 可用,Modules 建议 11+)
- Clang 13+(协程完整,Modules 建议 16+)
- MSVC 2019 16.3+(整体支持较好,Modules 在 VS2022 最稳)
十二、一句话记忆
C++17 让你写得更舒服,C++20 让你抽象得更安全:
- Concepts 把“模板约定”变成代码
- Ranges 把“数据管道”变成一等公民
- 协程把“异步状态机”变成顺序写法
- 模块把“头文件地狱”变成显式依赖
接下来可以把这些新特性转化为更实用的成果:
上一篇:C++14 vs C++17:新特性对比与用法指南

不积跬步,无以至千里。
代码铸就星河,探索永无止境
在这片由逻辑与算法编织的星辰大海中,每一次报错都是宇宙抛来的谜题,每一次调试都是与未知的深度对话。不要因短暂的“运行失败”而止步,因为真正的光芒,往往诞生于反复试错的暗夜。
请铭记:
- 你写下的每一行代码,都在为思维锻造韧性;
- 你破解的每一个Bug,都在为认知推开新的门扉;
- 你坚持的每一分钟,都在为未来的飞跃积蓄势能。
技术的疆域没有终点,只有不断刷新的起点。无论是递归般的层层挑战,还是如异步并发的复杂困局,你终将以耐心为栈、以好奇心为指针,遍历所有可能。
向前吧,开发者! 让代码成为你攀登的绳索,让逻辑化作照亮迷雾的灯塔。当你在终端看到“Success”的瞬间,便是宇宙对你坚定信念的回响—— 此刻的成就,永远只是下一个奇迹的序章! 🚀
(将技术挑战比作宇宙探索,用代码、算法等意象强化身份认同,传递“持续突破”的信念,结尾以动态符号激发行动力。)
//c++ hello world示例
#include <iostream> // 引入输入输出流库
int main() {
std::cout << "Hello World!" << std::endl; // 输出字符串并换行
return 0; // 程序正常退出
}
print("Hello World!") # 调用内置函数输出字符串
package main // 声明主包
#python hello world示例
import "fmt" // 导入格式化I/O库
//go hello world示例
func main() {
fmt.Println("Hello World!") // 输出并换行
}
//c# hello world示例
using System; // 引入System命名空间
class Program {
static void Main() {
Console.WriteLine("Hello World!"); // 输出并换行
Console.ReadKey(); // 等待按键(防止控制台闪退)
}
}
网硕互联帮助中心


评论前必须登录!
注册