云计算百科
云计算领域专业知识百科平台

C++20 vs C++17:新特性对比与用法指南

文章目录

  • 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(); // 等待按键(防止控制台闪退)
}
}

赞(0)
未经允许不得转载:网硕互联帮助中心 » C++20 vs C++17:新特性对比与用法指南
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!