学懂C++(六十):C++ 11、C++ 14、C++ 17、C++ 20新特性大总结(万字详解大全)

[复制链接]
发表于 2026-1-21 17:48:02 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
一、弁言

        随着盘算机科学与技能的飞速发展,编程语言也在不绝进化以满足日益增长的需求。C++是一门集高性能和机动性于一身的编程语言,自1983年诞生以来不绝演进,渐渐成为了浩繁范畴的主流编程语言。为了进一步提拔开发服从和代码质量,C++标准委员会不绝引入新的标准和特性。从C++11开始,C++语言进入了一个快速发展的时期,随后推出的C++14、C++17、C++20进一步丰富了语言特性和标准库功能。本文将对各个版本的C++标准中的新特性举行具体总结,资助开发者相识和把握这些新特性,从而更好地应用于实际项目中。

二、新特性简介

C++11 标准简介
        C++11(原名为C++0x)是C++语言的一次巨大更新,被广泛以为是自C++98以来最告急的版本。C++11引入了大量的新特性和改进,使得C++更加今世化和易用。重要特性包罗自动范例推导(auto 和 decltype)、Lambda表达式、右值引用和移动语义、智能指针、多线程支持(std::thread)以及范围 for 循环等。这些特性明显提拔了开发服从、代码的可读性和性能。
C++14 标准简介
        C++14是对C++11的一次增量更新,重要在C++11的根本上举行了改进和优化。C++14引入了一些新的语言特性和标准库增强,包罗泛型Lambda、decltype(auto)、变量模板、二进制字面量、睁开运算符(...)的增强以及 std::make_unique。这些改进使得C++语言更加机动和高效,同时也修正了一些C++11中的不敷之处。
C++17 标准简介
        C++17是C++语言的又一次告急更新,带来了许多新特性和标准库的扩展。新特性包罗布局化绑定(Structured Bindings)、折叠表达式(Fold Expressions)、if 和 switch 初始化、std:ptional、std::variant 和 std::any,以及并行STL算法和 std::filesystem。别的,还引入了嵌套定名空间(Nested Namespaces)和 constexpr 的扩展。C++17明显增强了语言的表达本领和标准库的功能,使得开发更加便捷和高效。
C++20 标准简介
        C++20是C++语言的一次巨大里程碑,被誉为C++11之后最告急的更新版本。C++20引入了许多全新的语言特性和标准库扩展,包罗概念(Concepts)、三方比力运算符(<=>)、范围库(Ranges)、协程(Coroutines)、模块(Modules)、计时器库增强(Calendar and Time Zone Library)、constinit 关键字、[[likely]] 和 [[unlikely]] 属性、以及 std::span 和 std::expected。这些新特性进一步提拔了C++的今世化程度,极大地增强了语言的机动性和开发服从。
三、C++11 新特性具体总结

1. 自动范例推断 (auto)
auto关键字答应编译器根据初始化表达式推断变量的范例,这使代码更简便且更易维护。
示例:
  1. auto x = 10; // x的类型推断为int
  2. auto y = 3.14; // y的类型推断为double
  3. std::vector<int> vec = {1, 2, 3};
  4. for (auto iter = vec.begin(); iter != vec.end(); ++iter) {
  5.     std::cout << *iter << std::endl;
  6. }
复制代码
背后的原理:
编译器在编译时会通过范例推断机制来确定auto变量的具体范例。auto通常用于简化复杂范例声明,特别是在模板和迭代器中非常有用。
2. 范围for循环 (Range-based for loop)
范围for循环让数组和容器的迭代更加简单和直观。
示例:
  1. std::vector<int> v = {1, 2, 3, 4, 5};
  2. for (auto i : v) {
  3.     std::cout << i << std::endl;
  4. }
复制代码
背后的原理:
范围for循环实在是一个语法糖,它在编译时会被转换成传统的迭代器循环。它对全部支持begin()和end()函数的容器都有用。
3. 智能指针 (Smart Pointers)
智能指针(如 std::shared_ptr 和 std::unique_ptr)管理资源的生命周期,防止内存走漏。
示例:
  1. std::shared_ptr<int> p1 = std::make_shared<int>(10);
  2. std::unique_ptr<int> p2 = std::make_unique<int>(20);
复制代码
背后的原理:
智能指针通过RAII(Resource Acquisition Is Initialization)机制管理资源。std::shared_ptr使用引用计数来管理资源共享,std::unique_ptr则是独占资源。
4. lambda表达式 (Lambda Expressions)
lambda表达式使得在局部创建匿名函数变得简单。
示例:
  1. auto add = [](int a, int b) { return a + b; };
  2. std::cout << add(2, 3) << std::endl; // 输出 5
复制代码
背后的原理:
lambda表达式是内联界说的匿名函数,编译器会天生一个类,该类实现operator()函数。捕获列表可以捕获外部作用域的变量。
5. 右值引用和移动语义 (Rvalue References and Move Semantics)
右值引用答应开发者实现移动语义,从而明显进步步调性能。
示例:
  1. void foo(std::string&& str) {
  2.     std::string local = std::move(str);
  3. }
复制代码
背后的原理:
右值引用使得对象在内存中的“移动”而不是拷贝成为大概。std::move函数将左值转换为右值引用,从而启用移动语义。
6. 标准线程库 (Thread Library)
C++11引入了一个跨平台的标准线程库。
示例:
  1. std::thread t([] { std::cout << "Hello from thread!" << std::endl; });
  2. t.join();
复制代码
背后的原理:
标准线程库提供了跨平台的线程管理接口。std::thread对象表现一个线程,并提供方法来启动和管理线程生命周期。
7. std::array 和 std::tuple
std::array是一个定长的数组类,std::tuple是一种可以存储多个差别范例值的固定巨细容器。
示例:
  1. std::array<int, 3> arr = {1, 2, 3};
  2. auto t = std::make_tuple(1, "hello", 3.14);
复制代码
背后的原理:
std::array和std::tuple提供了更安全和更机动的容器范例。std::tuple可以存储和访问差别范例的多个值,std::array则提供了比传统C数组更安全的接口。
8. 强范例罗列(Strongly-typed Enums)
C++11引入了enum class,提供了强范例罗列,克制了传统罗列的一些题目,如名称辩论和隐式转换。
示例:
  1. enum class Color { Red, Green, Blue };
  2. enum class TrafficLight { Red, Yellow, Green };
  3. Color color = Color::Red;
  4. TrafficLight light = TrafficLight::Green;
  5. // 不会发生隐式转换错误
  6. // if (color == light) { ... } // 编译错误
复制代码
背后的原理:
enum class在作用域内创建罗列值,而且不答应隐式转换为整数范例,如答应以提供更好的范例安全性。
9. 静态断言(Static Assert)
静态断言static_assert用于在编译时查抄条件,假如条件不满足则产生编译错误。
示例:
  1. static_assert(sizeof(int) == 4, "Integers must be 4 bytes");
复制代码
背后的原理:
static_assert是在编译时举行断言查抄,比运行时断言更高效。假如条件不创建,编译器会天生错误信息,从而防止天生无效代码。
10. nullptr
C++11引入了nullptr,这是一个范例安全的空指针。
示例:
  1. int* p = nullptr; // p是一个空指针
复制代码
背后的原理:
nullptr是一个特别范例的常量,表现空指针。与传统的NULL相比,nullptr可以与非指针范例的重载函数举行区分,消除了歧义。
11. 委托构造函数(Delegating Constructors)
构造函数可以委托给同一类的另一个构造函数,从而镌汰代码重复。
示例:
  1. class MyClass {
  2. public:
  3.     MyClass(int a, int b) : MyClass(a) {
  4.         // other initialization
  5.     }
  6.     MyClass(int a) {
  7.         // initialization
  8.     }
  9. };
复制代码
背后的原理:
委托构造函数答应一个构造函数调用另一个构造函数,如答应以共享初始化代码,镌汰代码重复,增强类的可维护性。
12. 继承构造函数(Inherited Constructors)
继承构造函数答应派生类继承基类的构造函数。
示例:
  1. class Base {
  2. public:
  3.     Base(int x) {}
  4. };
  5. class Derived : public Base {
  6.     using Base::Base; // 继承Base的构造函数
  7. };
复制代码
背后的原理:
继承构造函数通过using声明使得派生类可以继承基类的构造函数,从而简化构造函数的编写和维护。
13. 显式虚函数覆盖(Override)
使用override关键字明确表现派生类的成员函数是覆盖基类的虚函数。
示例:
  1. class Base {
  2. public:
  3.     virtual void foo() {}
  4. };
  5. class Derived : public Base {
  6. public:
  7.     void foo() override {
  8.         // implementation
  9.     }
  10. };
复制代码
背后的原理:
override关键字是给编译器的一个提示,明确表明此函数是用来覆盖基类的虚函数。假如基类函数的署名改变,编译器会产生错误,防止不测重载。
14. 删除函数(Deleted Functions)
可以使用= delete语法克制某些函数的使用。
示例:
  1. class NonCopyable {
  2. public:
  3.     NonCopyable(const NonCopyable&) = delete; // 禁止拷贝构造函数
  4.     NonCopyable& operator=(const NonCopyable&) = delete; // 禁止拷贝赋值运算符
  5. };
复制代码
背后的原理:
= delete语法用于显式禁用某些函数,从而在编译时克制这些函数的使用,增强类的安全性和可维护性。
15. 默认函数(Defaulted Functions)
可以使用= default语法显式声明默认的函数实现。
示例:
  1. class DefaultConstructor {
  2. public:
  3.     DefaultConstructor() = default; // 使用默认的构造函数
  4.     ~DefaultConstructor() = default; // 使用默认的析构函数
  5. };
复制代码
背后的原理:
= default语法用于显式哀求编译器天生默认实现,如答应以克制手动界说默认举动,镌汰代码量和埋伏错误。
16. 变长参数模板(Variadic Templates)
变长参数模板答应模板担当可变数量的模板参数。
示例:
  1. template<typename... Args>
  2. void print(Args... args) {
  3.     (std::cout << ... << args) << std::endl; // C++17引入的折叠表达式
  4. }
复制代码
背后的原理:
变长参数模板通过...语法担当多个参数,编译器会睁开这些参数并天生对应的代码。这在实现泛型函数和类时非常有用。
17. 同一的初始化语法(Uniform Initialization Syntax)
C++11引入了大括号初始化语法,使得初始化更同等。
示例:
  1. int arr[] = {1, 2, 3};
  2. std::vector<int> vec = {1, 2, 3};
  3. MyClass obj = {1, 2, 3}; // 假设MyClass有合适的构造函数
复制代码
背后的原理:
同一的初始化语法使用大括号举行初始化,支持数组、容器和类对象的初始化,使代码更同等、更易读。
18. 基于时间的随机数库(Random Number Generation)
C++11引入了新的随机数库,提供了更多的随机数天生器和分布范例。
示例:
  1. #include <random>
  2. std::random_device rd;
  3. std::mt19937 gen(rd());
  4. std::uniform_int_distribution<> dis(1, 6);
  5. int random_number = dis(gen); // 生成1到6之间的随机数
复制代码
背后的原理:
新的随机数库提供了更机动的随机数天生方式,包罗多种随机数天生器(如std::mt19937)和分布范例(如std::uniform_int_distribution),满足差别场景的需求。
19. noexcept 规范
noexcept 规范用于声明函数不会抛出非常,假如函数抛出了非常会导致步调停止。
示例:
  1. void foo() noexcept {
  2.     // this function is guaranteed not to throw exceptions
  3. }
  4. void bar() noexcept(false) {
  5.     // this function may throw exceptions
  6. }
复制代码
背后的原理:
noexcept 规范通过在编译时查抄函数是否大概抛出非常,从而优化代码天生。假如 noexcept 函数抛出了非常,std::terminate 会被调用,停止步调实行。
20. 范例别名模板(Alias Templates)
范例别名模板提供了一种更简便的模板范例界说方式。
示例:
  1. template<typename T>
  2. using Vec = std::vector<T>;
  3. Vec<int> v; // 等价于 std::vector<int> v;
复制代码
背后的原理:
范例别名模板通过 using 关键字界说新的范例别名,从而简化模板范例的使用,使代码更加简便和可读。
21. 尾置返回范例(Trailing Return Types)
尾置返回范例使得复杂返回范例的函数声明更易读。
示例:
  1. auto add(int a, int b) -> int {
  2.     return a + b;
  3. }
复制代码
背后的原理:
尾置返回范例将返回范例放在函数参数之后界说,使得复杂返回范例(特别是依赖模板参数的返回范例)的声明更加直观和可读。
22. 常量表达式(constexpr)
constexpr 关键字用于界说在编译时求值的常量表达式。
示例:
  1. constexpr int square(int x) {
  2.     return x * x;
  3. }
  4. constexpr int result = square(5); // 在编译时计算结果
复制代码
背后的原理:
constexpr 函数必须是纯函数(不产生副作用),而且只能调用其他constexpr函数或利用常量,从而包管在编译时可以求值。
23. 用户自界说字面量(User-defined Literals)
用户自界说字面量答应开发者界说新的字面量语法。
示例:
  1. constexpr long double operator"" _km(long double x) {
  2.     return x * 1000;
  3. }
  4. constexpr long double operator"" _m(long double x) {
  5.     return x;
  6. }
  7. constexpr long double operator"" _cm(long double x) {
  8.     return x / 100;
  9. }
  10. long double distance = 3.4_km + 150.0_m + 13.0_cm; // 距离单位转换
复制代码
背后的原理:
用户自界说字面量通过界说特定情势的 operator"" 函数来处置处罚新的字面量语法,从而扩展语言的字面量支持,增强代码可读性。
24. 右值引用成员函数(Rvalue Reference Member Functions)
右值引用成员函数答应对象在右值上下文中调用特定的成员函数。
示例:
  1. class MyClass {
  2. public:
  3.     void foo() & {
  4.         std::cout << "Left-value object" << std::endl;
  5.     }
  6.     void foo() && {
  7.         std::cout << "Right-value object" << std::endl;
  8.     }
  9. };
  10. MyClass obj;
  11. obj.foo(); // 输出 "Left-value object"
  12. MyClass().foo(); // 输出 "Right-value object"
复制代码
背后的原理:
右值引用成员函数通过 & 和 && 修饰符区分左右值上下文,使得类可以在差别上下文中实行差别利用,优化资源管理和性能。
25. 非静态数据成员初始化器(Non-static Data Member Initializers)
非静态数据成员初始化器答应在类界说中直接为成员变量提供初始值。
示例:
  1. class MyClass {
  2.     int x = 10; // 直接初始化
  3.     int y = 20;
  4. };
复制代码
背后的原理:
非静态数据成员初始化器使得成员变量的初始化更加简便,克制了在构造函数中举行重复初始化,增强代码可读性和维护性。
26. 标准库增强(Standard Library Enhancements)
C++11大幅增强了标准库,引入了一些新的容器和算法,改进了现有的库。
示例:
  1. #include <array>
  2. #include <unordered_map>
  3. #include <regex>
  4. #include <chrono>
  5. // std::array
  6. std::array<int, 3> arr = {1, 2, 3};
  7. // std::unordered_map
  8. std::unordered_map<std::string, int> umap;
  9. umap["one"] = 1;
  10. umap["two"] = 2;
  11. // std::regex
  12. std::regex re("\\w+");
  13. std::smatch match;
  14. std::string s = "hello world";
  15. if (std::regex_search(s, match, re)) {
  16.     std::cout << match[0] << std::endl; // 输出 "hello"
  17. }
  18. // std::chrono
  19. using namespace std::chrono;
  20. auto start = high_resolution_clock::now();
  21. // ... some operations ...
  22. auto end = high_resolution_clock::now();
  23. auto duration = duration_cast<milliseconds>(end - start).count();
  24. std::cout << "Duration: " << duration << " ms" << std::endl;
复制代码
背后的原理:
C++11标准库的增强为开发者提供了更多的工具和数据布局,使得开发高效、机动和可维护的代码更加轻易。

四、C++14 新特性具体总结

1. 泛型Lambda表达式(Generic Lambdas)
C++14扩展了lambda表达式的功能,使其可以或许担当模板参数,从而变得更加通用。
示例:
  1. auto add = [](auto a, auto b) {
  2.     return a + b;
  3. };
  4. std::cout << add(1, 2) << std::endl; // 输出 3
  5. std::cout << add(1.5, 2.5) << std::endl; // 输出 4.0
复制代码
背后的原理:
泛型lambda表达式使用 auto 关键字来表现恣意范例的参数,编译器会根据通报的参数范例自动天生模板代码。这大大进步了lambda表达式的机动性和通用性。
2. 二进制字面量(Binary Literals)
C++14引入了二进制字面量,使得编写和阅读二进制数据更加方便。
示例:
  1. int binary_value = 0b1010; // 等价于十进制的10
  2. std::cout << binary_value << std::endl; // 输出 10
复制代码
背后的原理:
二进制字面量通过前缀 0b 或 0B 来表现,使得开发者可以更直观地界说和明白二进制数据,特别是在嵌入式体系和底层编程中非常有用。
3. 数字分隔符(Digit Separators)
C++14引入了单引号作为数字字面量的分隔符,使得长数字更易读。
示例:
  1. int largeNumber = 1'000'000; // 等价于1000000
  2. std::cout << largeNumber << std::endl; // 输出 1000000
复制代码
背后的原理:
数字分隔符通过在数字字面量中插入单引号来分隔数字,这不会影响数字的值,但明显进步了长数字的可读性和维护性。
4. constexpr的增强(Extended constexpr)
C++14增强了 constexpr 的功能,使得 constexpr 函数可以包罗更多的语句和逻辑。
示例:
  1. constexpr int factorial(int n) {
  2.     if (n <= 1) return 1;
  3.     else return n * factorial(n - 1);
  4. }
  5. constexpr int result = factorial(5); // 在编译时计算结果
复制代码
背后的原理:
C++14的 constexpr 使得函数可以包罗循环、条件语句等复杂逻辑,从而编写更强大的编译时盘算代码,提拔了代码的性能和机动性。
5. 返回范例推断(Return Type Deduction)
C++14引入了返回范例推断功能,使得编译器可以自动推断函数的返回范例。
示例:
  1. auto add(int a, int b) {
  2.     return a + b;
  3. }
  4. std::cout << add(1, 2) << std::endl; // 输出 3
复制代码
背后的原理:
返回范例推断通过 auto 关键字使得编译器根据函数体内容自动推断返回范例,从而简化了函数的界说,特别实用于返回范例复杂或依赖模板参数的环境。
6. decltype(auto)
C++14引入了 decltype(auto) 关键字,使得返回范例推断更加机动和精确。
示例:
  1. int x = 5;
  2. decltype(auto) y = x; // y的类型为int
  3. decltype(auto) z = (x); // z的类型为int&
  4. std::cout << y << std::endl; // 输出 5
  5. std::cout << z << std::endl; // 输出 5
复制代码
背后的原理:
decltype(auto) 联合了 auto 和 decltype 的特性,使得编译器可以根据表达式的范例和值种别(左值/右值)来精确推断变量或返回值的范例。
7. 渐渐初始化捕获(Generalized Lambda Capture)
C++14扩展了lambda表达式的捕获机制,使得可以直接捕获并初始化变量。
示例:
  1. int x = 10;
  2. auto lambda = [y = x + 5]() {
  3.     return y;
  4. };
  5. std::cout << lambda() << std::endl; // 输出 15
复制代码
背后的原理:
渐渐初始化捕获通过在捕获列表中使用 = 或 & 举行初始化,使得lambda表达式可以捕获并初始化变量,从而增强了lambda表达式的机动性和可读性。
8. 标准库增强(Standard Library Enhancements)
C++14对标准库举行了一些增强和改进,增长了更多实用的功能和容器。
示例:
  1. #include <shared_mutex>
  2. #include <make_unique>
  3. // std::shared_timed_mutex
  4. std::shared_timed_mutex mutex;
  5. std::shared_lock<std::shared_timed_mutex> lock(mutex);
  6. // std::make_unique
  7. auto ptr = std::make_unique<int>(10);
  8. std::cout << *ptr << std::endl; // 输出 10
复制代码
背后的原理:
C++14的标准库增强引入了更多线程管理和资源管理工具,如 std::shared_timed_mutex 和 std::shared_lock,以及 std::make_unique 等方便的工厂函数,提拔了代码的可维护性和性能。
9. std::integer_sequence 和 std::make_integer_sequence
C++14引入了 std::integer_sequence 和 std::make_integer_sequence,用于天生整数序列,常用于模板元编程。
示例:
  1. #include <utility>
  2. #include <iostream>
  3. template<typename T, T... Ints>
  4. void print_sequence(std::integer_sequence<T, Ints...>) {
  5.     ((std::cout << Ints << ' '), ...);
  6. }
  7. int main() {
  8.     print_sequence(std::make_integer_sequence<int, 5>{}); // 输出 0 1 2 3 4
  9.     return 0;
  10. }
复制代码
背后的原理:
std::integer_sequence 和 std::make_integer_sequence 提供了一个天生整数序列的工具,极大地方便了模板元编程,特别是在处置处罚参数包和编译时盘算时非常有用。

五、C++17 新特性具体总结

1. 布局化绑定声明(Structured Bindings)
C++17引入告终构化绑定声明,使得可以将布局或元组的元素绑定到独立的变量中。
示例:
  1. #include <tuple>
  2. #include <iostream>
  3. std::tuple<int, double, std::string> getTuple() {
  4.     return std::make_tuple(42, 3.14, "hello");
  5. }
  6. int main() {
  7.     auto [i, d, s] = getTuple();
  8.     std::cout << i << ", " << d << ", " << s << std::endl; // 输出 42, 3.14, hello
  9.     return 0;
  10. }
复制代码
背后的原理:
布局化绑定通过在变量声明时使用 auto 关键字和方括号,将布局或元组的元素解包并绑定到独立的变量上,从而简化代码,增强可读性。
2. if 和 switch 初始化语句(If and Switch Initialization Statements)
C++17答应在 if 和 switch 语句中举行初始化,从而镌汰代码范围,提拔可读性。
示例:
  1. if (std::vector<int> vec = {1, 2, 3}; !vec.empty()) {
  2.     std::cout << "Vector is not empty" << std::endl;
  3. }
  4. switch (int n = 42; n) {
  5.     case 1:
  6.         std::cout << "One" << std::endl;
  7.         break;
  8.     case 42:
  9.         std::cout << "Forty-Two" << std::endl;
  10.         break;
  11.     default:
  12.         std::cout << "Other" << std::endl;
  13.         break;
  14. }
复制代码
背后的原理:
if 和 switch 初始化语句通过引入初始化部门,使得在判断条件语句前可以举行变量的声明和初始化,从而缩小变量的作用域,增强代码可维护性。
3. 内联变量(Inline Variables)
C++17引入了内联变量关键字 inline,用来声明在多个翻译单位中共享的变量。
示例:
  1. inline int global_counter = 0;
  2. void increment() {
  3.     ++global_counter;
  4. }
复制代码
背后的原理:
内联变量通过 inline 关键字使得变量在多个翻译单位中共享界说,克制链接错误,增强全局变量的可用性。
4. 折叠表达式(Fold Expressions)
C++17引入了折叠表达式,简化了对参数包的利用。
示例:
  1. template<typename... Args>
  2. auto sum(Args... args) {
  3.     return (args + ...); // 右折叠
  4. }
  5. int main() {
  6.     std::cout << sum(1, 2, 3, 4, 5) << std::endl; // 输出 15
  7.     return 0;
  8. }
复制代码
背后的原理:
折叠表达式通过 ... 语法简化了对可变参数模板包的利用,支持左折叠和右折叠两种情势,镌汰了代码的冗余和复杂性。
5. std:ptional
C++17引入了 std:ptional,用于表现一个大概包罗值大概为空的对象。
示例:
  1. #include <optional>
  2. #include <iostream>
  3. std::optional<int> findValue(bool found) {
  4.     if (found) return 42;
  5.     else return std::nullopt;
  6. }
  7. int main() {
  8.     auto value = findValue(true);
  9.     if (value) {
  10.         std::cout << "Value: " << *value << std::endl; // 输出 42
  11.     } else {
  12.         std::cout << "Value not found" << std::endl;
  13.     }
  14.     return 0;
  15. }
复制代码
背后的原理:
std:ptional 提供了一种安全的方式来处置处罚大概为空的值,克制了空指针非常和非须要的默认值,进步了代码的安全性和可读性。
6. std::variant
C++17引入了 std::variant,一种范例安全的连合体,可以存储多种范例中的一种。
示例:
  1. #include <variant>
  2. #include <iostream>
  3. std::variant<int, double, std::string> getValue(bool condition) {
  4.     if (condition) return 42;
  5.     else return "hello";
  6. }
  7. int main() {
  8.     auto value = getValue(true);
  9.     if (std::holds_alternative<int>(value)) {
  10.         std::cout << "Integer: " << std::get<int>(value) << std::endl; // 输出 42
  11.     } else if (std::holds_alternative<std::string>(value)) {
  12.         std::cout << "String: " << std::get<std::string>(value) << std::endl;
  13.     }
  14.     return 0;
  15. }
复制代码
背后的原理:
std::variant 提供了一种范例安全的方式来处置处罚多个大概的范例,克制了传统连合体的范例安全题目,增强了代码的结实性和可维护性。
7. std::any
C++17引入了 std::any,可以存储恣意范例的对象。
示例:
  1. #include <any>
  2. #include <iostream>
  3. int main() {
  4.     std::any value = 42;
  5.     if (value.type() == typeid(int)) {
  6.         std::cout << "Integer: " << std::any_cast<int>(value) << std::endl; // 输出 42
  7.     }
  8.     value = std::string("hello");
  9.     if (value.type() == typeid(std::string)) {
  10.         std::cout << "String: " << std::any_cast<std::string>(value) << std::endl; // 输出 hello
  11.     }
  12.     return 0;
  13. }
复制代码
背后的原理:
std::any 提供了一种机动的方式来存储恣意范例的对象,通过范例安全的访问机制(如 std::any_cast),克制了范例错误,增强了代码的机动性和安全性。
8. std::string_view
C++17引入了 std::string_view,这是一个轻量级的不可变字符串视图,克制了不须要的字符串拷贝。
示例:
  1. #include <string_view>
  2. #include <iostream>
  3. void printStringView(std::string_view str) {
  4.     std::cout << str << std::endl;
  5. }
  6. int main() {
  7.     std::string s = "hello world";
  8.     printStringView(s); // 输出 hello world
  9.     return 0;
  10. }
复制代码
背后的原理:
std::string_view 提供了一种高效的方式来利用字符串数据,克制了字符串拷贝的开销,实用于只读字符串利用,提拔了性能和代码的可读性。
9. std::filesystem
C++17引入了标准文件体系库 std::filesystem,提供了一组高效便捷的文件和目次利用API。
示例:
  1. #include <filesystem>
  2. #include <iostream>
  3. int main() {
  4.     std::filesystem::path p = "/tmp";
  5.     if (std::filesystem::exists(p)) {
  6.         std::cout << "Directory exists" << std::endl;
  7.     }
  8.     for (const auto& entry : std::filesystem::directory_iterator(p)) {
  9.         std::cout << entry.path() << std::endl;
  10.     }
  11.     return 0;
  12. }
复制代码
背后的原理:
std::filesystem 提供了跨平台的文件和目次利用API,包罗路径利用、文件状态查询、目次遍历等,大大简化了文件体系相干的编程任务。
10. 并行算法(Parallel Algorithms)
C++17引入了并行算法,通过扩展标准库算法,支持多线程并行实行。
示例:
  1. #include <algorithm>
  2. #include <vector>
  3. #include <execution>
  4. #include <iostream>
  5. int main() {
  6.     std::vector<int> vec(1000, 1);
  7.     std::for_each(std::execution::par, vec.begin(), vec.end(), [](int& n) { n++; });
  8.     std::cout << "Sum: " << std::accumulate(vec.begin(), vec.end(), 0) << std::endl; // 输出 2000
  9.     return 0;
  10. }
复制代码
背后的原理:
并行算法通过支持并行实行战略(如 std::execution::par 和 std::execution::par_unseq),使用多线程和硬件加快,明显提拔了算法的实行服从和性能。

六、C++20 新特性具体总结

1. 概念(Concepts)
C++20引入了概念(Concepts),用于束缚模板参数,进步模板代码的可读性和错误查抄本领。
示例:
  1. #include <concepts>
  2. #include <iostream>
  3. template<typename T>
  4. concept Integral = std::is_integral_v<T>;
  5. template<Integral T>
  6. T add(T a, T b) {
  7.     return a + b;
  8. }
  9. int main() {
  10.     std::cout << add(1, 2) << std::endl; // 输出 3
  11.     // std::cout << add(1.0, 2.0) << std::endl; // 编译错误,因为double不是Integral
  12.     return 0;
  13. }
复制代码
背后的原理:
概念通过 concept 关键字界说,并联合模板参数,使得模板代码在编译时举行束缚查抄,克制不符合条件的范例通报,提拔模板代码的安全性和可读性。
2. 三方比力运算符(<=>)(Three-way Comparison Operator)
C++20引入了三方比力运算符(<=>),用于简化和同一比力利用。
示例:
  1. #include <iostream>
  2. #include <compare>
  3. struct Point {
  4.     int x, y;
  5.     auto operator<=>(const Point&) const = default;
  6. };
  7. int main() {
  8.     Point p1{1, 2};
  9.     Point p2{1, 3};
  10.     if (p1 < p2) {
  11.         std::cout << "p1 is less than p2" << std::endl;
  12.     } else if (p1 == p2) {
  13.         std::cout << "p1 is equal to p2" << std::endl;
  14.     } else {
  15.         std::cout << "p1 is greater than p2" << std::endl;
  16.     }
  17.     return 0;
  18. }
复制代码
背后的原理:
三方比力运算符(<=>)天生同一的比力利用符,使得对象的比力更加简便和同等,支持 <, <=, ==, !=, >=, > 这些利用符。
3. 范围库(Ranges)
C++20引入了范围库(Ranges),大大简化了对聚集和序列的利用。
示例:
  1. #include <ranges>
  2. #include <vector>
  3. #include <iostream>
  4. int main() {
  5.     std::vector<int> vec = {1, 2, 3, 4, 5};
  6.     auto even_numbers = vec | std::ranges::views::filter([](int n) { return n % 2 == 0; });
  7.     for (int n : even_numbers) {
  8.         std::cout << n << std::endl; // 输出 2 4
  9.     }
  10.     return 0;
  11. }
复制代码
背后的原理:
范围库通过引入 views 和 actions,使得对聚集和序列的利用更加直观和简便,增强了代码的可读性和机动性。
4. 协程(Coroutines)
C++20引入了协程(Coroutines),用于简化异步编程和天生器的实现。
示例:
  1. #include <coroutine>  // 包含协程支持
  2. #include <iostream>   // 包含输入输出支持
  3. #include <optional>   // 包含 std::optional(在这段代码中未使用,但通常有用)
  4. // 协程生成器类
  5. struct Generator {
  6.     // 定义协程的 promise_type
  7.     struct promise_type {
  8.         int current_value;  // 存储当前生成的值
  9.         // 协程挂起并返回值
  10.         std::suspend_always yield_value(int value) {
  11.             current_value = value;
  12.             return {};
  13.         }
  14.         // 协程初始挂起
  15.         std::suspend_always initial_suspend() { return {}; }
  16.         // 协程最终挂起
  17.         std::suspend_always final_suspend() noexcept { return {}; }
  18.         // 获取生成器对象
  19.         Generator get_return_object() { return Generator{this}; }
  20.         // 返回 void,因为生成器不返回值
  21.         void return_void() {}
  22.         // 处理未捕获的异常
  23.         void unhandled_exception() {}
  24.     };
  25.     // 迭代器用于遍历生成器生成的值
  26.     struct iterator {
  27.         std::coroutine_handle<promise_type> handle;  // 协程句柄
  28.         bool done;  // 标记协程是否完成
  29.         // 前置递增运算符用于推进协程
  30.         iterator& operator++() {
  31.             handle.resume();  // 恢复协程
  32.             done = handle.done();  // 更新完成状态
  33.             return *this;
  34.         }
  35.         // 解引用运算符返回当前值
  36.         int operator*() const { return handle.promise().current_value; }
  37.         // 比较运算符用于结束迭代
  38.         bool operator!=(const iterator&) const { return !done; }
  39.     };
  40.     // 返回生成器的开始迭代器
  41.     iterator begin() {
  42.         handle.resume();  // 恢复协程以获取第一个值
  43.         return iterator{handle, handle.done()};
  44.     }
  45.     // 返回生成器的结束迭代器
  46.     iterator end() { return iterator{handle, true}; }
  47.     // 协程句柄
  48.     std::coroutine_handle<promise_type> handle;
  49. };
  50. // 协程函数,生成从 1 到 max 的整数序列
  51. Generator counter(int max) {
  52.     for (int i = 1; i <= max; ++i) {
  53.         co_yield i;  // 生成值并挂起协程
  54.     }
  55. }
  56. // 主函数,测试生成器
  57. int main() {
  58.     for (int value : counter(5)) {
  59.         std::cout << value << std::endl;  // 输出 1 2 3 4 5
  60.     }
  61.     return 0;
  62. }
复制代码
代码表明:


  •         包罗头文件:
    1. #include <coroutine>
    2. #include <iostream>
    3. #include <optional>
    复制代码

    • #include <coroutine>:用于C++协程支持。
    • #include <iostream>:用于输入输出利用。
    • #include <optional>:固然未在代码中使用,但通常有用。

  •         界说 Generator 类:

    • promise_type 布局体:

      • int current_value;:存储当前天生的值。
      • std::suspend_always yield_value(int value);:协程挂起并返回值。
      • std::suspend_always initial_suspend();:协程初始挂起。
      • std::suspend_always final_suspend() noexcept;:协程终极挂起。
      • Generator get_return_object();:返回天生器对象。
      • void return_void();:天生器不返回值。
      • void unhandled_exception();:处置处罚未捕获的非常。

    • iterator 布局体:

      • std::coroutine_handle<promise_type> handle;:协程句柄。
      • bool done;:标记协程是否完成。
      • iterator& operator++();:前置递增运算符,用于推进协程。
      • int operator*() const;:解引用运算符,返回当前值。
      • bool operator!=(const iterator&) const;:比力运算符,用于竣事迭代。

    • begin 和 end 方法:

      • iterator begin();:返回天生器的开始迭代器。
      • iterator end();:返回天生器的竣事迭代器。


  •         界说协程函数 counter:
    1. Generator counter(int max) {
    2.     for (int i = 1; i <= max; ++i) {
    3.         co_yield i;
    4.     }
    5. }
    复制代码

    • 天生从1到max的整数序列。

  •         主函数 main:
    1. int main() {
    2.     for (int value : counter(5)) {
    3.         std::cout << value << std::endl; // 输出 1 2 3 4 5
    4.     }
    5.     return 0;
    6. }
    复制代码

    • 使用 for 循环遍历天生器天生的值,并输出它们。


背后的原理:
协程通过 co_await, co_yield 和 co_return 关键字,使得函数可以在中心挂起和规复实行,从而简化了异步利用和天生器的实现,提拔了代码的可维护性和性能。
5. 模块(Modules)
C++20引入了模块(Modules),用于替换传统的头文件机制,进步编译速率和模块化程度。
示例:
  1. // example.ixx
  2. export module example;
  3. export int add(int a, int b) {
  4.     return a + b;
  5. }
  6. // main.cpp
  7. import example;
  8. #include <iostream>
  9. int main() {
  10.     std::cout << add(1, 2) << std::endl; // 输出 3
  11.     return 0;
  12. }
复制代码
背后的原理:
模块通过 export 和 import 关键字,引入模块化机制,办理了头文件的重复编译题目,进步了编译速率和代码的模块化程度。
6. 计时器库增强(Calendar and Time Zone Library)
C++20引入了增强的计时器库,支持日历和时区利用。
示例:
  1. #include <chrono>
  2. #include <iostream>
  3. int main() {
  4.     using namespace std::chrono;
  5.     auto now = system_clock::now();
  6.     auto today = floor<days>(now);
  7.     std::cout << "Today: " << today.time_since_epoch().count() << std::endl; // 输出自纪元以来的天数
  8.     return 0;
  9. }
复制代码
背后的原理:
增强的计时器库通过引入 std::chrono 的新工具和范例,使得日历和时区利用更加直观和便捷,提拔了代码的时间处置处罚本领。
7. constinit 关键字
C++20引入了 constinit 关键字,用于确保变量在编译时初始化。
示例:
  1. constinit int global_value = 42;
  2. int main() {
  3.     std::cout << global_value << std::endl; // 输出 42
  4.     return 0;
  5. }
复制代码
背后的原理:
constinit 关键字确保变量在编译时完成初始化,克制未初始化变量的使用,增强了代码的安全性和可猜测性。
8. [[likely]] 和 [[unlikely]] 属性
C++20引入了 [[likely]] 和 [[unlikely]] 属性,用于提示编译器哪条分支更大概被实行,从而优化分支猜测。
示例:
  1. #include <iostream>
  2. int main() {
  3.     int n = 42;
  4.     if (n == 42) [[likely]] {
  5.         std::cout << "Likely branch" << std::endl;
  6.     } else [[unlikely]] {
  7.         std::cout << "Unlikely branch" << std::endl;
  8.     }
  9.     return 0;
  10. }
复制代码
背后的原理:
[[likely]] 和 [[unlikely]] 属性通过提示编译器举行分支猜测优化,从而提拔代码的运行服从,特别是在性能关键的代码路径中。
9. std::span
C++20引入了 std::span,一个轻量级的视图,可以非拥有地访问连续的元素。
示例:
  1. #include <span>
  2. #include <iostream>
  3. #include <vector>
  4. void printSpan(std::span<int> sp) {
  5.     for (int n : sp) {
  6.         std::cout << n << " ";
  7.     }
  8.     std::cout << std::endl;
  9. }
  10. int main() {
  11.     std::vector<int> vec = {1, 2, 3, 4, 5};
  12.     printSpan(vec); // 输出 1 2 3 4 5
  13.     int arr[] = {6, 7, 8, 9, 10};
  14.     printSpan(arr); // 输出 6 7 8 9 10
  15.     return 0;
  16. }
复制代码
背后的原理:
std::span 提供了一种高效的方式来访问连续内存中的元素,克制了不须要的拷贝和全部权管理,提拔了代码的性能和机动性。
10. 错误传播(std::expected)
C++20引入了 std::expected,用于表现大概乐成或错误的效果,极大简化了错误处置处罚。
示例:
  1. #include <iostream>
  2. #include <expected> // 包含<std::expected>头文件,需要C++23或支持该功能的编译器
  3. // 定义一个函数 divide,用于进行两个整数的除法操作,并返回一个 std::expected 类型的结果
  4. std::expected<int, std::string> divide(int a, int b) {
  5.     // 检查除数是否为零
  6.     if (b == 0)
  7.         // 如果除数为零,返回一个 std::unexpected 对象,包含错误信息 "Division by zero"
  8.         return std::unexpected("Division by zero");
  9.    
  10.     // 如果除数不为零,返回商
  11.     return a / b;
  12. }
  13. int main() {
  14.     // 调用 divide 函数,进行 10 除以 2 的操作
  15.     auto result = divide(10, 2);
  16.    
  17.     // 检查 result 是否包含一个有效值
  18.     if (result) {
  19.         // 如果 result 有效,解引用 result 并打印结果
  20.         std::cout << "Result: " << *result << std::endl; // 输出 5
  21.     } else {
  22.         // 如果 result 无效,打印错误信息
  23.         std::cout << "Error: " << result.error() << std::endl;
  24.     }
  25.     return 0;
  26. }
复制代码
示例表明:

  •         包罗头文件:
    1. #include <iostream>
    2. #include <expected>
    复制代码

    • #include <iostream> 用于输入输出利用。
    • #include <expected> 用于 std::expected。

  •         界说 divide 函数:
    1. std::expected<int, std::string> divide(int a, int b) {
    2.     if (b == 0)
    3.         return std::unexpected("Division by zero");
    4.     return a / b;
    5. }
    复制代码

    • 担当两个整数 a 和 b。
    • 假如 b 为零,返回错误信息 "Division by zero"。
    • 否则,返回 a 除以 b 的效果。

  •         主函数:
    1. int main() {
    2.     auto result = divide(10, 2);
    3.     if (result) {
    4.         std::cout << "Result: " << *result << std::endl;
    5.     } else {
    6.         std::cout << "Error: " << result.error() << std::endl;
    7.     }
    8.     return 0;
    9. }
    复制代码

    • 调用 divide 函数,实行 10 除以 2。
    • 查抄 result 是否有用:

      • 假如有用,打印效果。
      • 假如无效,打印错误信息。


这段代码演示了怎样使用 std::expected 来处置处罚大概的错误环境,比方除以零的错误。
背后的原理:
std::expected 提供了一种范例安全的方式来处置处罚大概乐成或失败的利用,克制了非常的使用,提拔了代码的结实性和可读性。
这些是C++20中的重要新特性,它们在提拔语言机动性、简化代码和增强性能方面都有明显作用。C++20的引入标记着C++语言的又一次告急进化,进一步增强了其作为今世编程语言的职位。


七、总结

        从C++11到C++20,每一次标准更新都带来了大量的新特性和改进,使得C++语言更加今世化和强大。这些新特性不但提拔了开发服从和代码质量,还极大地增强了语言的表达本领和机动性。通过引入自动范例推导、Lambda表达式、智能指针、并行STL算法、协程、模块等功能,C++渐渐成为了更得当今世软件开发的语言。相识并把握这些新特性,可以资助开发者在实际项目中更好地应用C++,从而开发出更加高效和可靠的软件体系。将来的C++标准还将继承演进,我们等候C++23及以后的版本可以或许带来更加丰富和实用的功能,为开发者提供更好的编程体验。
        盼望本文可以或许资助你全面相识C++各个版本的新特性,并在实际开发中充实使用这些功能。无论是初学者还是履历丰富的开发者,深入明白并应用这些新特性,都是提拔编程技能和开发服从的关键。

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表