目录
C++ 的发展总结:编辑
1. C++ 的早期发展(1979-1985)
2. C++ 标准化过程(1985-1998)
3. C++ 标准演化(2003-2011)
4. C++11(2011年)
5. C++14(2014年)
6. C++17(2017年)
7. C++20(2020年)
8. C++23(2023年)
1. C++ 1985: C++ 1.0
主要特性:
示例代码:
代码讲解:
C++ 1.0 的局限性:
总结:
2. C++ 1989: C++ 2.0
主要特性:
多重继承与虚继承
示例代码:
代码讲解:
运行输出:
解释:
C++ 2.0 的局限性:
总结:
3. C++ 1990: C++ 3.0
主要特性:
模板的引入
示例代码:模板示例
代码讲解:
运行输出:
代码解释:
模板的优势:
C++ 3.0 的局限性:
总结:
4. C++ 1998: C++98
主要特性:
示例代码:C++98 的常见特性
代码讲解:
运行输出:
代码解释:
C++98 的局限性:
总结:
5. C++ 2003: C++03
主要特性和变化:
C++03 与 C++98 的区别:
示例代码:C++98 和 C++03 的差异
示例代码:模板特化修复和 SFINAE 改进
代码解释:
运行输出:
C++03 与 C++98 的局限性:
总结:
6. C++ 2011: C++11
主要新特性:
示例代码:C++11 特性
代码解释:
运行输出:
C++11 的优势:
C++11 的局限性:
总结:
7. C++ 2014: C++14
主要新特性:
示例代码:C++14 新特性
代码解释:
运行输出:
C++14 的优势:
C++14 的局限性:
总结:
8. C++ 2017: C++17
1. 结构化绑定声明 (Structured Bindings)
示例:
2. if/else语句中的初始化语句 (If/else with initialization)
示例:
3. std::optional
示例:
4. std::string_view
示例:
5. std::filesystem
示例:
6. 并行算法 (Parallel Algorithms)
示例:
7. 内联变量 (Inline Variables)
示例:
8. 改进的constexpr
示例:
总结
9. C++ 2020: C++20
1. 概念 (Concepts)
示例:
2. 范围 (Ranges)
示例:
3. 协程 (Coroutines)
示例:
4. 三向比较 (Spaceship Operator <=>)
示例:
5. 模块 (Modules)
示例:
6. 范围循环 (Range-based for loop with initializer)
示例:
7. std::span
示例:
8. consteval 和 constinit
示例:
总结
10. C++ 2023: C++23
1. 改进的常量表达式(constexpr)
示例:
2. std::expected
示例:
3. 范围(Ranges)库增强
示例:
4. std::format 改进
示例:
5. explicit 改进
示例:
6. std::span 支持的改进
示例:
7. 新的属性([[likely]] 和 [[unlikely]])
示例:
总结
C++ 的发展总结:
C++ 是由 Bjarne Stroustrup 于 1979 年在贝尔实验室(Bell Labs)开始开发的,最初是作为 C 语言的一个扩展,目的是在不丧失 C 语言高效性的基础上,提供面向对象编程的特性。C++ 的发展历程可以分为以下几个重要阶段:
C++ 的早期发展 | 1979-1985 |
C++ 标准化过程 | 1985-1998 |
C++ 标准演化 | 2003-2011 |
C++11 | 2011年 |
C++14 | 2014年 |
C++17 | 2017年 |
C++20 | 2020年 |
C++23 | 2023年 |
1. C++ 的早期发展(1979-1985)
1979年:C++ 的前身 "C with Classes" 出现。Bjarne Stroustrup 在贝尔实验室的工作中,设计了一个扩展 C 语言的工具,该工具为 C 语言增加了类(class)、构造函数和析构函数等面向对象特性。它的设计目标是提高程序的可重用性,并通过封装数据和方法的方式增强程序结构。1983年:C with Classes 更名为 **C++**,并发布了第一版 C++ 语言,开始引入类、继承、多态等面向对象的特性,虽然这些特性并不完善,但已经为后来的发展奠定了基础。1985年:C++ 语言的第一个标准版本发布。Stroustrup 为此编写了《C++ Programming Language》一书,详细介绍了 C++ 的语法、特性和编程模型。2. C++ 标准化过程(1985-1998)
1989年:C++ 的第一个国际标准草案发布,作为一种较为成熟的语言,逐渐被越来越多的开发者使用。1990年:C++ 被纳入国际标准化组织(ISO)的标准化过程。这个过程中,C++ 逐步加入了更多的语言特性,如模板、异常处理、名字空间等。1998年:C++98 标准发布,这是 C++ 语言的第一个正式标准版本。C++98 通过增加模板支持、标准库(如 STL)和异常处理机制,使得 C++ 语言更加全面和功能强大,成为当时最主流的编程语言之一。3. C++ 标准演化(2003-2011)
2003年:C++03 标准发布,主要是对 C++98 标准的修正和小幅改进,修复了一些语言特性中的小错误,并未引入重大的新特性。2007年:ISO 发布了 C++0x 标准草案,该标准最终演变为 C++11。在 C++0x 的过程中,许多新的特性开始得到提出和采纳,如 自动类型推导、右值引用、lambda 表达式、并发编程 等。C++11 的标准化过程历时多年,经历了大量的讨论和修改。4. C++11(2011年)
2011年:C++11 正式发布,它是 C++ 语言的一个重大变革,包含了大量的新特性,标志着 C++ 语言进入了一个全新的时代。C++11 的主要特性包括: 自动类型推导(auto
);右值引用和移动语义(&&
、std::move
);Lambda 表达式;线程支持(std::thread
);智能指针(std::unique_ptr
、std::shared_ptr
);类型推导(decltype
)等。C++11 的引入极大提升了 C++ 语言的表达力和现代化程度,使得 C++ 编程更具灵活性和高效性。 5. C++14(2014年)
2014年:C++14 发布,相较于 C++11,C++14 更像是一个小规模的优化和修复版本。C++14 主要增强了 C++11 中的特性,如 Lambda 表达式的泛型支持、std::make_unique
的引入、decltype(auto)
的改进等。此外,还修复了一些编译器和实现中的问题。C++14 让 C++11 中的很多新特性变得更加稳定,增加了可编程性和工具支持。 6. C++17(2017年)
2017年:C++17 发布,这个版本包含了一些有意义的语言特性和标准库增强。主要特性包括: **std::optional
**:用于表示可能为空的值;结构化绑定声明(auto [a, b] = tuple;
);if
和 switch
中的初始化语句;**std::filesystem
**:用于处理文件和目录的标准库;**改进的 std::string
和 std::array
**;并行算法(std::for_each
等支持并行执行)。C++17 不仅增强了语言本身的功能,还进一步加强了对现代硬件和多核处理器的支持,增强了性能和并行计算能力。 7. C++20(2020年)
2020年:C++20 发布,是 C++ 语言历史上一个非常重要的版本,带来了许多令人兴奋的新特性: 模块(Modules):改善头文件管理,减少编译时间;三方比较操作符(<=>
): 用于自动生成比较操作符(比如 ==
, !=
, <
, <=
, >
, >=
);协程(Coroutines):使得异步编程更加简洁;概念(Concepts):提供更强的类型约束机制,使模板编程更加安全;范围 for 循环改进:更简洁的语法和强大的灵活性;**std::span
**:处理数组和内存块的轻量级对象;改进的标准库:包括 std::format
、std::ranges
、std::calendar
等。C++20 为 C++ 带来了大量的现代化特性,并进一步提升了语言的表达能力、性能和并发编程的支持。 8. C++23(2023年)
2023年:C++23 发布,虽然其变化相较于 C++20 比较平稳,但仍然包含了一些重要的改进和修复: 新的标准库功能:例如,std::expected
、std::generator
和 std::ranges
的进一步改进;语言增强:对模板和类型推导的改进,增强了语言的灵活性和可读性;性能优化:进一步增强编译器对并行、异步和内存管理的支持。C++23 标志着 C++ 语言持续向现代化发展,并且对性能和并发编程的支持进一步加强。 从面向过程到面向对象:最初的 C++ 语言只是在 C 语言的基础上增加了类和面向对象的特性,经过多年发展,C++ 在保留 C 语言高效性的同时,也吸收了面向对象、泛型编程和函数式编程的优势,成为了一门多范式的语言。
标准化过程:从 C++98 到 C++11,再到 C++14、C++17 和 C++20,C++ 逐渐成为一种具有广泛应用的编程语言,每个版本都带来了一些新的特性和增强,逐步适应现代软件开发的需求。
现代化与性能:C++ 在引入面向对象特性后,也逐步加入了并行计算、内存管理、泛型编程、协程等现代编程特性,使得它在高性能计算、系统开发、游戏开发和金融等领域仍然占有一席之地。
C++ 的发展历程体现了它强大的灵活性和持久生命力,C++ 不断演进,始终保持着与时俱进的能力,成为全球使用最广泛的编程语言之一。
C++ 的发展历程可以分为多个版本阶段,每个版本都带来了新的语言特性、库的改进和标准的增强。下面是 C++ 各个版本的主要变化和特性介绍:
1. C++ 1985: C++ 1.0
最初版本:由贝尔实验室的 Bjarne Stroustrup 在 1980 年代初期开发。主要特点: 在 C 语言的基础上加入了面向对象编程(OOP)特性。支持类、继承、多态、封装等面向对象的基本特性。引入了函数和运算符重载。C++ 1.0 是由 Bjarne Stroustrup 在贝尔实验室开发的第一版 C++ 编程语言。它是在 C 语言的基础上加入了面向对象编程(OOP)的特性,因此也被称为是“C with Classes”(C 带类)。C++ 1.0 并不是一个标准化的语言版本,而是一个实验性语言,它为后来的 C++ 标准奠定了基础。
主要特性:
类与对象:C++ 1.0 引入了面向对象编程的核心概念,最初的类和对象支持比较简单。
类是 C++ 中的基本构造,用于封装数据和功能。对象是类的实例,表示实际的数据和行为。函数和运算符重载:C++ 1.0 支持函数重载和运算符重载,使得程序员可以根据需要定义不同版本的函数或操作符。
基本继承:C++ 1.0 支持从一个类继承另一个类,使得可以构建更为复杂的类结构。
无标准库:当时的 C++ 语言没有像现代 C++ 那样的标准库。数据结构和算法通常依赖开发者自己编写。
示例代码:
C++ 1.0 版本的代码相对简单。以下是一个典型的 C++ 1.0 示例,演示了类的定义、对象创建、继承以及运算符重载。
#include <iostream>using namespace std;// 定义一个类class Box {private: double length; // 长度 double breadth; // 宽度 double height; // 高度public: // 构造函数 Box(double l, double b, double h) { length = l; breadth = b; height = h; } // 计算体积的方法 double volume() { return length * breadth * height; } // 运算符重载 Box operator+(const Box& b) { // 返回一个新的 Box 对象,体积相加 return Box(length + b.length, breadth + b.breadth, height + b.height); }};// 主函数int main() { // 创建对象 Box box1(3.5, 1.2, 2.0); Box box2(1.0, 2.0, 3.0); // 计算并输出 box1 的体积 cout << "Box1 Volume: " << box1.volume() << endl; // 运算符重载使用示例 Box box3 = box1 + box2; cout << "Box3 Volume (box1 + box2): " << box3.volume() << endl; return 0;}
代码讲解:
**类Box
**:定义了一个包含 length
、breadth
和 height
的类,用于表示一个盒子,并且提供了一个计算体积的方法 volume()
。构造函数:用于初始化 Box
对象,设置它的长度、宽度和高度。运算符重载:使用 operator+
重载运算符 +
,使得两个 Box
对象相加时,返回一个新的 Box
对象,长度、宽度和高度分别相加。在 main()
中创建对象:通过构造函数创建了 box1
和 box2
,并计算它们的体积。在计算 box3
的体积时,使用了重载的加法运算符。 C++ 1.0 的局限性:
缺少模板:当时的 C++ 并不支持模板(泛型编程),模板编程是后来在 C++ 1990 和 1998 标准中引入的。没有标准库:没有现代 C++ 的 STL(标准模板库),因此没有常用的容器、算法等功能。继承的支持较为基础:C++ 1.0 支持继承,但还没有引入多态、虚函数等更高级的特性。总结:
C++ 1.0 是 C++ 语言的初步版本,它为面向对象编程提供了基础设施,并通过类、对象、继承、重载等功能扩展了 C 语言的功能。虽然当时的 C++ 功能较为简单,但它为后续版本的语言特性打下了基础,并引领了 C++ 向更强大的方向发展。
2. C++ 1989: C++ 2.0
增强功能: 多重继承:支持多个基类的继承。虚继承:解决多重继承中的“菱形继承”问题,确保继承层次中的基类只有一份副本。抽象类:引入了纯虚函数(抽象类)的概念,使得类能够定义接口。C++ 2.0 是 C++ 语言的第二个重要版本,发布于 1989 年。C++ 2.0 在 C++ 1.0 的基础上进行了重要的扩展和改进,引入了多个新特性,特别是 多重继承 和 虚继承。这些新特性使得 C++ 的面向对象编程能力得到了显著增强。C++ 2.0 为后来的 C++ 语言标准奠定了许多重要基础。
主要特性:
多重继承:C++ 2.0 引入了多重继承的支持,使得一个类可以继承多个基类,从而可以组合多个类的功能。虚继承:为了解决多重继承带来的“菱形继承”问题(即一个类通过多个继承路径继承同一个基类),C++ 2.0 引入了 虚继承 的概念。虚继承确保通过多个继承路径继承的同一个基类只有一份副本。虚函数:继续扩展了对面向对象编程的支持,尤其是通过 虚函数 机制,使得 C++ 支持 运行时多态。更强的类型检查:C++ 2.0 对类型检查进行了增强,使得语言的类型系统更加严格和安全。多重继承与虚继承
C++ 2.0 的最大变化之一就是支持 多重继承,并且引入了 虚继承 来解决多重继承可能引起的问题。在多重继承中,如果一个类继承自多个基类,并且这些基类有公共的祖先类,那么在派生类中会有重复的祖先类副本,这时就可能出现问题。虚继承解决了这一问题,通过确保只有一个祖先类副本,从而避免了数据冗余和潜在的错误。
示例代码:
以下是一个简单的示例,演示了 多重继承 和 虚继承 的概念。
#include <iostream>using namespace std;// 基类Aclass A {public: A() { cout << "Class A constructor" << endl; } void showA() { cout << "Class A" << endl; }};// 基类Bclass B {public: B() { cout << "Class B constructor" << endl; } void showB() { cout << "Class B" << endl; }};// 基类C,虚继承Aclass C : virtual public A {public: C() { cout << "Class C constructor" << endl; } void showC() { cout << "Class C" << endl; }};// 派生类D,虚继承A和Bclass D : public C, public B {public: D() { cout << "Class D constructor" << endl; } void showD() { cout << "Class D" << endl; }};int main() { // 创建派生类对象D D d; d.showA(); // 来自基类A d.showB(); // 来自基类B d.showC(); // 来自基类C d.showD(); // 来自派生类D return 0;}
代码讲解:
类 A 和 B:A
和 B
是两个基类,都有自己的构造函数和成员函数。A
有一个 showA()
函数,B
有一个 showB()
函数。类 C:C
类继承了 A
类,并使用 virtual
关键字进行 虚继承。这样,在 C
的子类中,如果有多个继承自 A
的路径,它们会共享同一个 A
类副本,避免了重复数据。类 D:D
类从 C
和 B
继承,并且通过虚继承机制共享了 A
类的副本。输出: 当 D
类的对象被创建时,首先调用 A
、B
和 C
的构造函数,再调用 D
的构造函数。showA()
、showB()
和 showC()
分别调用了从基类继承的成员函数。 运行输出:
Class A constructorClass B constructorClass C constructorClass D constructorClass AClass BClass CClass D
解释:
虚继承:C
类通过 virtual public A
虚继承了 A
类,保证了通过 D
类的继承关系,A
类只有一份副本。即使 D
类是通过 B
和 C
两个路径继承 A
,A
类也只会被构造一次。多重继承:D
类通过多重继承继承了 B
和 C
,因此 D
类拥有 B
和 C
类的功能。 C++ 2.0 的局限性:
没有命名空间:C++ 2.0 并没有引入命名空间(namespace),因此容易出现命名冲突的问题。没有模板支持:模板编程(如函数模板和类模板)在 C++ 2.0 中还没有出现,这一特性是在 C++ 3.0 中引入的。继承体系较为简化:虽然支持多重继承和虚继承,但对继承体系的支持仍较为基础,随着 C++ 后续版本的发布,继承和多态的功能会得到更完善的支持。总结:
C++ 2.0 通过引入 多重继承 和 虚继承 大大增强了 C++ 的面向对象能力,使得 C++ 成为一种更强大的编程语言。这些特性让 C++ 能够支持更复杂的类层次结构,解决了多重继承中的一些难题。虽然 C++ 2.0 语言仍然很基础,但它为 C++ 后续版本的更高级特性,如模板和更复杂的类型系统,奠定了基础。
3. C++ 1990: C++ 3.0
功能增强: 模板:引入了模板(函数模板和类模板),开始支持泛型编程。标准库:初步支持了标准模板库(STL)的概念,虽然 STL 直到后来的版本才成为标准。C++ 3.0 是 C++ 语言的第三个版本,发布于 1990 年。相比于前两个版本,C++ 3.0 在语言特性和功能上做出了重要的扩展,最为关键的就是引入了 模板 的支持,这是 C++ 语言向 泛型编程 过渡的重要一步。模板的引入使得 C++ 支持编写与类型无关的代码,从而使得编程变得更加灵活和强大。
主要特性:
模板(Templates):
函数模板:允许定义可以接受不同类型参数的函数。类模板:允许定义可以接受不同类型参数的类。模板是 C++ 语言中泛型编程的基础。增强的类型系统:
支持更复杂的类型定义和类型推导。改进了类和对象的类型推断机制。基本的标准库(STL的雏形):
尽管 C++ 3.0 本身并没有正式定义标准模板库(STL),但它开始支持类似 STL 的一些容器和算法概念,为未来 STL 的引入奠定了基础。支持虚函数、运算符重载等特性:
C++ 3.0 继续扩展了面向对象编程的支持,增强了对继承、多态、运算符重载等特性的支持。模板的引入
C++ 3.0 的核心改进就是引入了模板机制,使得函数和类能够接受参数类型作为模板参数。这使得 C++ 能够支持泛型编程,从而能够编写类型安全且重用性更高的代码。
示例代码:模板示例
以下是一个简单的示例,展示了如何在 C++ 3.0 中使用 函数模板 和 类模板。
#include <iostream>using namespace std;// 函数模板:计算两个数字的最大值template <typename T>T getMax(T a, T b) { return (a > b) ? a : b;}// 类模板:定义一个简单的容器类template <typename T>class Box {private: T value;public: Box(T v) : value(v) {} T getValue() { return value; } void setValue(T v) { value = v; }};int main() { // 使用函数模板 int x = 10, y = 20; cout << "Max of x and y: " << getMax(x, y) << endl; double a = 3.14, b = 2.71; cout << "Max of a and b: " << getMax(a, b) << endl; // 使用类模板 Box<int> intBox(100); cout << "Box contains: " << intBox.getValue() << endl; intBox.setValue(200); cout << "Updated Box contains: " << intBox.getValue() << endl; Box<double> doubleBox(3.14159); cout << "Box contains: " << doubleBox.getValue() << endl; return 0;}
代码讲解:
**函数模板 getMax
**:
getMax
是一个函数模板,它接受两个类型为 T
的参数,返回它们中的最大值。T
是一个类型参数,可以是任何数据类型(如 int
、double
等),当调用模板函数时,编译器会根据传入的参数类型推导出 T
的具体类型。 **类模板 Box
**:
Box
是一个类模板,它有一个类型为 T
的成员变量 value
。构造函数接受一个 T
类型的参数来初始化 value
,并提供了 getValue
和 setValue
方法来访问和修改 value
。 运行输出:
Max of x and y: 20Max of a and b: 3.14Box contains: 100Updated Box contains: 200Box contains: 3.14159
代码解释:
getMax
函数模板:在 main()
中,分别使用了 int
和 double
类型的参数来调用 getMax
函数模板。编译器根据传入的参数类型推导出 T
的类型。Box
类模板:Box<int>
和 Box<double>
分别是使用 int
和 double
类型的类模板实例化出来的对象。每个 Box
对象可以存储不同类型的数据。 模板的优势:
代码重用:通过模板,函数和类可以支持多种不同的类型,而不需要为每个类型编写重复的代码。类型安全:模板在编译时进行类型检查,确保类型的正确性,避免了运行时的类型错误。C++ 3.0 的局限性:
模板特性较为基础:C++ 3.0 中的模板机制较为简单,没有现代 C++ 中复杂的模板特性,如模板特化、SFINAE(Substitution Failure Is Not An Error)等。标准库仍然不成熟:尽管模板提供了更多的灵活性,但标准库并没有像 C++11 和 C++14 中那样强大,STL 的概念才刚刚开始萌芽。总结:
C++ 3.0 是 C++ 语言的一个重要版本,模板的引入是其最大的亮点,标志着 C++ 进入了泛型编程的时代。模板让 C++ 变得更加灵活,支持更加高效的代码重用和类型安全的操作。通过函数模板和类模板,C++ 可以在不同类型之间共享代码,从而极大地提高了开发效率和代码的可维护性。虽然 C++ 3.0 的模板机制相对简单,但它为后续的 C++ 标准化进程和更复杂的模板特性奠定了基础。
4. C++ 1998: C++98
C++ 标准化:C++98 是 C++ 的第一个正式标准版本,由 ISO/IEC 14882:1998 定义。主要特性: STL(标准模板库):引入了标准模板库,包括vector
、list
、map
、set
等容器,及算法(如排序、查找等)。map - C++ Reference set - C++ Reference命名空间(namespace):为了避免名称冲突,引入了命名空间。异常处理:引入了 try
、catch
、throw
异常处理机制。RTTI(运行时类型信息):引入了 typeid
和 dynamic_cast
,允许运行时识别对象的类型。 C++98 是 C++ 语言的第一个国际标准,正式由 ISO(国际标准化组织)在 1998 年发布。C++98 语言标准继承了 C++ 3.0 的核心特性,并在此基础上进行了多个重要的改进和规范化。这个版本的 C++ 为标准库(STL)提供了规范,并开始支持更多的现代编程特性。
主要特性:
模板:
C++98 中的模板特性得到了进一步的增强,支持函数模板和类模板,并且模板的使用变得更加广泛。模板参数可以是类、函数、指针等类型。标准模板库(STL)
sort - C++ Reference
异常处理:
C++98 提供了标准化的异常处理机制,使用try
, catch
, throw
语句来处理运行时错误。 命名空间:
C++98 引入了 命名空间(namespace
),用于避免名称冲突,尤其是在大型项目中。 虚函数与多态:
C++98 继续强化了面向对象编程的支持,特别是对 虚函数 和 多态 的使用。const 和引用:
C++98 对const
关键字和引用进行了严格的规范,使得编程更加安全。 函数指针和类型转换:
提供了对 函数指针 和 类型转换(如static_cast
, dynamic_cast
等)的支持,增强了 C++ 的灵活性。 类成员的类型推导:
C++98 引入了对类成员类型的推导,允许在某些情况下省略类型声明。示例代码:C++98 的常见特性
以下是一个综合示例,展示了 C++98 中的几个核心特性,包括模板、标准库(STL)、命名空间和异常处理。
vector - C++ Reference
#include <iostream>#include <vector>#include <algorithm>#include <stdexcept>namespace MyNamespace { // 模板函数:计算两个数的最大值 template <typename T> T getMax(T a, T b) { return (a > b) ? a : b; } // 使用 STL 容器:vector 和算法 void useSTL() { std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; std::sort(vec.begin(), vec.end()); std::cout << "Sorted vector: "; for (int num : vec) { std::cout << num << " "; } std::cout << std::endl; } // 异常处理示例 void testException() { try { throw std::out_of_range("Index out of range!"); } catch (const std::exception& e) { std::cout << "Caught exception: " << e.what() << std::endl; } }}int main() { // 使用命名空间 using namespace MyNamespace; // 使用模板函数 int x = 10, y = 20; std::cout << "Max of x and y: " << getMax(x, y) << std::endl; // 使用 STL 容器和算法 useSTL(); // 测试异常处理 testException(); return 0;}
代码讲解:
**模板函数 getMax
**:
typename T
表示这是一个模板函数,T
是占位符类型,可以在调用时由编译器自动推导出。 STL 容器和算法:
在useSTL
函数中,使用了 std::vector
来存储整数数据,并使用 std::sort
算法对数据进行了排序。std::vector
是 C++98 标准库中的一个动态数组容器,std::sort
是一个算法函数,用于对容器中的元素进行排序。 异常处理:
testException
函数演示了 C++98 的异常处理机制。在这个函数中,抛出了一个 std::out_of_range
异常,并在 catch
块中捕获它,输出异常的描述信息。 运行输出:
Max of x and y: 20Sorted vector: 1 1 2 3 3 4 5 5 5 6 9 Caught exception: Index out of range!
代码解释:
**模板getMax
**:通过模板,可以在运行时自动确定 T
的类型,支持不同的数据类型(如 int
、double
等)。在本例中,它比较了两个整数 x
和 y
。**STL 容器 std::vector
和 std::sort
**:std::vector
是一个可以动态调整大小的容器,它存储一系列元素。std::sort
是一个通用算法,用来对容器中的元素进行排序。异常处理:C++98 提供了标准的异常处理机制,允许在代码运行过程中抛出和捕获异常,避免程序因错误而崩溃。 C++98 的局限性:
没有auto
关键字:C++98 中没有 auto
关键字,因此类型推导只能依靠显式的类型声明。**没有 nullptr
**:C++98 中没有 nullptr
,指针使用时可能会引发隐式的类型转换问题。没有类型推导的 for
循环:C++98 中没有像 C++11 中那样的基于范围的 for
循环(for (auto& elem : container)
)。模板元编程有限:虽然模板功能在 C++98 中已被引入,但对于模板元编程的支持相对有限,模板编程的复杂性和灵活性较低。 总结:
C++98 是 C++ 语言的第一个国际标准版本,它巩固并标准化了之前 C++3.0 中的许多特性,并加入了 模板 和 STL 等重要特性,使得 C++ 在实际开发中更加高效和灵活。通过模板,C++98 使得代码可以在不同的数据类型之间重用,同时标准库(STL)提供了高效的容器和算法支持,大大提高了开发效率。虽然 C++98 为后来的 C++ 标准奠定了基础,但它在某些领域(如模板编程和自动类型推导)仍存在局限。
5. C++ 2003: C++03
修复和改进: 小的改进:C++03 主要是对 C++98 标准的一些修订和错误修正,没有引入重大新特性。支持一些新的编译器特性,如增强的模板支持、异常安全性等。C++03 是 C++ 语言的一个小版本更新,它是对 C++98 的修正版本,主要用于解决一些语言上的不一致性和设计上的小问题。C++03 并未引入许多新的功能,而是对 C++98 标准中的一些细节进行了修正和澄清,确保语言的一致性和规范性。这个版本主要集中在语言规范的完善和一些编译器支持方面。
C++03 的发布并没有像 C++98 到 C++11 之间的版本那样进行革命性的更新,因此它在功能上与 C++98 并无太大差异。主要的更新包括对 模板特化、SFINAE(Substitution Failure Is Not An Error)等方面的细节修正,确保了编译器能够更好地支持标准库。
主要特性和变化:
模板的修正和改进:
C++03 对模板特化和模板元编程做了小的修正,使得编译器对模板的支持更加一致。改进了模板在某些边界情况中的行为,避免了 C++98 中一些不一致或令人困惑的部分。标准库的修正:
C++03 对标准库中的一些接口做了微调,解决了 C++98 标准库中的一些小问题。例如,修复了std::vector
在某些情况下的行为不一致性,确保了 STL 中的算法与容器的更好兼容性。 修复了常见的编译器问题:
C++03 对一些编译器的兼容性问题进行了修复,确保不同厂商的编译器之间有更好的兼容性。去除了某些不再使用的特性:
C++03 删除了一些在 C++98 中冗余或未被广泛使用的特性,从而使标准更加精简和一致。C++03 与 C++98 的区别:
细节修正:C++03 主要是针对 C++98 标准中存在的某些歧义性和编译器实现差异进行修正。它并没有加入新的语言特性,而是专注于优化语言和标准库的现有特性。STL 和模板的完善:C++03 解决了模板和标准库的一些小问题,确保标准库在不同编译器下的行为一致。示例代码:C++98 和 C++03 的差异
由于 C++03 与 C++98 的差异主要体现在语言的细节上,因此以下示例代码在 C++03 中的表现与 C++98 是相同的。我们展示一些在 C++98 和 C++03 中模板使用的常见问题,这些问题在 C++03 中得到了修正。
示例代码:模板特化修复和 SFINAE
改进
#include <iostream>#include <type_traits>// 模板类的默认实现template <typename T>class Printer {public: static void print(const T& value) { std::cout << value << std::endl; }};// 特化:对于 const 类型的处理template <typename T>class Printer<const T> {public: static void print(const T& value) { std::cout << "const value: " << value << std::endl; }};// 使用 SFINAE 来选择函数template <typename T>typename std::enable_if<!std::is_integral<T>::value, void>::typeprintType(const T& value) { std::cout << "Non-integer value: " << value << std::endl;}template <typename T>typename std::enable_if<std::is_integral<T>::value, void>::typeprintType(const T& value) { std::cout << "Integer value: " << value << std::endl;}int main() { Printer<int>::print(123); // 默认模板 Printer<const int>::print(456); // 特化模板 printType(123); // 调用整数版本 printType(3.14); // 调用非整数版本 return 0;}
代码解释:
模板类 Printer
的特化:
Printer
是一个模板类,在默认情况下,它的 print
函数打印任意类型的值。特化版本 Printer<const T>
对 const
类型的处理进行了特殊化,使其输出时带有 "const value: " 字样。此特化是在 C++03 中明确规定的,确保了特化行为的统一性。 SFINAE(Substitution Failure Is Not An Error):
printType
函数使用了 SFINAE 来根据类型 T
的不同选择不同的版本。
使用 std::enable_if
和 std::is_integral
来判断 T
是否为整数类型,并分别调用不同的函数。SFINAE
机制可以避免无效的模板实例化,确保了代码的类型安全。
如果 T
是整数类型,printType(int)
会被调用;否则,printType(double)
会被调用。
运行输出:
123const value: 456Integer value: 123Non-integer value: 3.14
C++03 与 C++98 的局限性:
没有新的语言特性:C++03 仅仅是 C++98 的修正版本,没有引入新的语言特性。开发者并未从中获得像 C++11、C++14、C++17 那样的重大进展。标准库的改进有限:虽然 C++03 修复了一些标准库的问题,但与后来的 C++ 标准相比,它的功能仍显得较为简单。没有现代化工具:如auto
、nullptr
、范围 for
循环等特性都没有出现在 C++03 中,这使得它在一些现代编程需求面前显得有些过时。 总结:
C++03 是一个对 C++98 的修正版本,主要修复了一些语言规范中的小错误和不一致性,改进了模板、STL 和编译器的兼容性。它并没有引入新的语言特性,因此在实际使用中,C++98 和 C++03 的差异并不显著。C++03 主要对 C++98 的一些不明确之处进行了修正,为后续 C++ 标准的进化(如 C++11、C++14)奠定了基础。对于开发者来说,C++03 更多的是一种稳定性和兼容性更新,而不是一种功能性扩展。
6. C++ 2011: C++11
现代 C++ 的起点:C++11 是 C++ 的一次重大更新,被广泛认为是 C++ 语言的“现代化”转折点。关键特性: 自动类型推断(auto
):使用 auto
关键字可以让编译器推断变量类型。智能指针:引入了 std::unique_ptr
、std::shared_ptr
、std::weak_ptr
,用于自动管理内存,避免内存泄漏。Lambda 表达式:允许定义匿名函数,可以在代码中更方便地使用函数对象。并发支持:引入了 <thread>
库,允许多线程编程。**nullptr
**:引入了 nullptr
关键字,替代 NULL
,提高代码的类型安全。右值引用和移动语义:引入右值引用(&&
)和 std::move
,提高对象传递效率,减少不必要的拷贝。范围 for 循环:引入了简洁的范围 for
循环,简化容器遍历。类型别名(using
):引入 using
关键字,简化类型别名定义。变长模板(Variadic Templates):支持可变参数模板,提高模板的灵活性。 C++11 是 C++ 语言的一个重大更新,正式于 2011 年发布。它引入了大量新的特性和改进,使 C++ 语言更现代化、更加高效和易于使用。C++11 标准的推出,极大地扩展了 C++ 的功能,使得 C++ 开发变得更加灵活、简洁,同时还提升了性能。
主要新特性:
自动类型推导(auto
):
auto
关键字允许编译器根据表达式的类型自动推导变量的类型,减少了类型声明的冗余,提高了代码可读性。 右值引用与移动语义(&&
和 std::move
):
&&
)和 std::move
,实现了 移动语义。通过移动资源而不是复制,显著提高了效率,尤其在需要大量数据传输的场合(如容器操作)。 范围 for
循环:
for
循环(range-based for loop),简化了容器元素的遍历,避免了传统迭代器的复杂性。 Lambda 表达式:
Lambda 表达式允许在函数内定义匿名函数,并且可以捕获外部变量,极大地增强了函数式编程的支持。**nullptr
**:
nullptr
替代了 NULL
,它是一个类型安全的空指针常量,消除了 NULL
的类型不匹配问题。 **constexpr
**:
constexpr
使得可以在编译时求值的常量表达式更加简洁,增强了编译期计算的能力。 并发编程:<thread>
库:
<thread>
库使得多线程编程变得更加容易和高效。 类型别名(using
):
using
关键字可以用来为类型定义别名,取代了传统的 typedef
,语法更加简洁。 强类型枚举(enum class
):
enum class
,避免了传统枚举可能产生的隐式转换和命名冲突问题。 **新标准库:std::chrono
**:
std::chrono
,使得处理时间变得更加直观和精确。 示例代码:C++11 特性
下面的代码示例展示了 C++11 的一些关键特性。
#include <iostream>#include <vector>#include <algorithm>#include <thread>#include <functional>// 1. 自动类型推导void autoExample() { auto x = 10; // 编译器自动推导类型为 int auto y = 3.14; // 编译器自动推导类型为 double std::cout << "x: " << x << ", y: " << y << std::endl;}// 2. 范围 for 循环void rangeBasedFor() { std::vector<int> vec = {1, 2, 3, 4, 5}; for (auto& num : vec) { // 使用范围 for 遍历 num *= 2; } std::cout << "Doubled values: "; for (const auto& num : vec) { std::cout << num << " "; } std::cout << std::endl;}// 3. Lambda 表达式void lambdaExample() { std::vector<int> vec = {1, 2, 3, 4, 5}; int sum = 0; // 使用 lambda 表达式进行求和 std::for_each(vec.begin(), vec.end(), [&sum](int num) { sum += num; }); std::cout << "Sum of elements: " << sum << std::endl;}// 4. 移动语义和右值引用class MyClass {public: MyClass() { std::cout << "Constructor\n"; } MyClass(const MyClass&) { std::cout << "Copy Constructor\n"; } MyClass(MyClass&&) { std::cout << "Move Constructor\n"; } MyClass& operator=(const MyClass&) { std::cout << "Copy Assignment\n"; return *this; } MyClass& operator=(MyClass&&) { std::cout << "Move Assignment\n"; return *this; }};void moveExample() { MyClass a; MyClass b = std::move(a); // 使用移动构造函数}int main() { // 自动类型推导 autoExample(); // 范围 for 循环 rangeBasedFor(); // Lambda 表达式 lambdaExample(); // 移动语义 moveExample(); // 使用线程 std::thread t([]{ std::cout << "Hello from a thread!\n"; }); t.join(); // 等待线程执行完毕 return 0;}
代码解释:
**自动类型推导 (auto
)**:
auto
关键字,编译器会自动推导变量 x
和 y
的类型,简化了类型声明,特别是对于复杂类型(如迭代器和函数返回类型)时非常有用。 范围 for
循环:
for
循环来遍历容器。这个语法简洁、直观,避免了显式的迭代器操作。 Lambda 表达式:
使用std::for_each
算法与 lambda 表达式结合,计算容器中所有元素的总和。lambda 表达式 [&sum](int num) { sum += num; }
捕获外部变量 sum
并对容器中的每个元素执行加法操作。 右值引用与移动语义:
在moveExample
中,通过 std::move
实现了对象 a
的移动,将其资源转移给对象 b
,触发了移动构造函数而不是拷贝构造函数。 线程支持:
使用 C++11 的<thread>
库创建和启动一个线程,并且通过 join()
等待线程执行完成。std::thread
简化了多线程编程。 运行输出:
x: 10, y: 3.14Doubled values: 2 4 6 8 10Sum of elements: 15Move ConstructorHello from a thread!
C++11 的优势:
现代化的语法和功能:C++11 引入的众多新特性大大提升了语言的灵活性和表达力,减少了冗余代码,使得 C++ 编程更加简洁、易读和高效。性能优化:通过右值引用和移动语义,C++11 使得许多数据传输和复制操作得以高效地优化,特别是在容器和大型对象的操作中,性能大幅提升。并发支持:C++11 将多线程支持纳入语言标准,使得并发编程变得更加容易和可靠,减少了对外部库的依赖。C++11 的局限性:
学习曲线:尽管 C++11 引入了许多现代化特性,但对一些开发者来说,掌握这些新特性可能需要一定的学习时间。编译器支持问题:尽管大部分现代编译器已经完全支持 C++11,但一些旧的编译器或开发环境可能存在兼容性问题。总结:
C++11 是 C++ 语言的一次重大更新,带来了许多新的语言特性和库支持,使得 C++ 编程变得更加简洁、强大和高效。无论是在性能优化、现代语法的引入,还是在并发支持等方面,C++11 都大幅提升了语言的可用性和表达能力。
7. C++ 2014: C++14
小幅增强:constexpr
的改进:支持更复杂的编译时常量计算。二进制字面量:引入了支持二进制常量字面量。auto
的增强:使得 auto
可以推导更加复杂的类型。Lambda 表达式的改进:支持更强的捕获特性(如捕获 *this
引用)。 C++14 是 C++ 语言的一个相对较小的更新版本,于 2014 年发布。C++14 并没有像 C++11 那样引入大量的新特性,而是对 C++11 中的一些特性进行了修复、增强和小幅优化。它的目标是提高语言和标准库的稳定性,改进一些 C++11 的边界情况,增强编译器的支持,并提供一些性能上的提升。
主要新特性:
泛型 Lambda 表达式:
C++14 扩展了 C++11 中的 Lambda 表达式,引入了泛型 Lambda,使得 Lambda 可以接受不同类型的参数而不需要显式地指定类型。变量模板:
C++14 引入了 变量模板,允许创建像模板函数一样的模板变量。之前只有函数和类可以是模板,但 C++14 使得变量也可以具有模板特性。Lambda 表达式的返回类型推导:
在 C++14 中,Lambda 表达式可以通过auto
关键字自动推导返回类型。这避免了在 Lambda 表达式中手动指定返回类型的需要。 **std::make_unique
**:
std::make_unique
,作为 std::make_shared
的对称操作,它简化了对 std::unique_ptr
的创建,避免了不必要的 new
运算符。 **decltype(auto)
**:
decltype(auto)
作为函数返回类型的推导方式,它可以推导出具有精确类型的返回值,支持返回引用类型的自动推导。 标准库改进:
C++14 修复了 C++11 标准库中的一些问题,并改进了对各种常见编译器的支持。标准库中对线程、智能指针、算法等的支持变得更加稳定和高效。二进制字面量:
C++14 引入了二进制字面量(0b
或 0B
)的支持,使得表示二进制数更加直观。 **std::exchange
**:
std::exchange
函数,它可以简化交换操作,尤其是当你需要交换一个对象并返回其原值时。 示例代码:C++14 新特性
以下代码展示了 C++14 中的一些关键特性,包括泛型 Lambda、变量模板、decltype(auto)
、std::make_unique
等。
#include <iostream>#include <vector>#include <memory>#include <algorithm>// 1. 泛型 Lambda 表达式void genericLambda() { auto sum = [](auto a, auto b) { return a + b; }; // 泛型 Lambda std::cout << "Sum of 3 and 4.5: " << sum(3, 4.5) << std::endl;}// 2. 变量模板template <typename T>T pi = T(3.14159);void variableTemplate() { std::cout << "Pi as float: " << pi<float> << std::endl; std::cout << "Pi as double: " << pi<double> << std::endl;}// 3. Lambda 表达式的返回类型推导void lambdaReturnType() { auto multiply = [](auto a, auto b) { return a * b; }; std::cout << "Multiply 4 and 5.5: " << multiply(4, 5.5) << std::endl;}// 4. 使用 std::make_uniquevoid makeUnique() { auto ptr = std::make_unique<int[]>(5); // 使用 make_unique 创建动态数组 ptr[0] = 10; std::cout << "First element in unique_ptr array: " << ptr[0] << std::endl;}// 5. 使用 decltype(auto) 推导返回类型int&& returnRvalue() { int x = 5; return std::move(x); // 返回右值引用}void decltypeAuto() { decltype(auto) result = returnRvalue(); std::cout << "Rvalue returned: " << result << std::endl;}// 6. 使用 std::exchangeint increment(int& x) { return std::exchange(x, x + 1); // 将 x 的当前值赋给函数并更新 x}void exchangeExample() { int value = 10; int oldValue = increment(value); std::cout << "Old value: " << oldValue << ", New value: " << value << std::endl;}int main() { // 泛型 Lambda genericLambda(); // 变量模板 variableTemplate(); // Lambda 返回类型 lambdaReturnType(); // 使用 make_unique makeUnique(); // 使用 decltype(auto) decltypeAuto(); // 使用 std::exchange exchangeExample(); return 0;}
代码解释:
泛型 Lambda 表达式:
通过auto
来声明 Lambda 表达式的参数类型,使得 Lambda 可以接受任意类型的参数。这使得 Lambda 表达式更加灵活,可以应用于多种不同的类型。 变量模板:
pi
是一个模板变量,它接受一个类型参数 T
,并为每个类型提供不同的常量值。在 variableTemplate()
中,演示了如何使用模板变量来获取 pi
的不同类型值。 Lambda 返回类型推导:
使用auto
关键字,Lambda 表达式会自动推导返回类型。在 lambdaReturnType()
中,返回类型是乘积结果的类型,auto
会自动推导出其正确类型。 **std::make_unique
**:
std::make_unique
用于创建 std::unique_ptr
,这是一个智能指针,用于管理动态分配的内存。std::make_unique
是 C++14 引入的,它比直接使用 new
更加安全和方便。 **decltype(auto)
**:
decltype(auto)
用于推导函数的返回类型,并且支持返回值是引用的情况。在 decltypeAuto()
中,returnRvalue()
返回一个右值引用,通过 decltype(auto)
可以正确地推导出返回类型。 **std::exchange
**:
std::exchange
是 C++14 引入的一个小工具,它用于交换一个变量的值并返回旧值。在 exchangeExample()
中,std::exchange
用于交换 value
的值并返回交换前的值。 运行输出:
Sum of 3 and 4.5: 7.5Pi as float: 3.14159Pi as double: 3.14159Multiply 4 and 5.5: 22First element in unique_ptr array: 10Rvalue returned: 5Old value: 10, New value: 11
C++14 的优势:
增强的类型推导:通过auto
、decltype(auto)
、泛型 Lambda 表达式等新特性,C++14 提供了更加灵活和精简的编程体验。更强大的 Lambda 表达式:C++14 使得 Lambda 表达式支持更复杂的类型推导和捕获方式,提升了函数式编程的能力。内存管理优化:std::make_unique
提高了内存管理的安全性和效率,避免了直接使用 new
时可能出现的资源泄漏问题。简化的交换操作:std::exchange
使得交换操作更加简洁,尤其是在需要交换并返回原值的场景中。 C++14 的局限性:
更新较小:相比 C++11,C++14 的新特性较少,更多的是对 C++11 特性的增强和补充。因此,C++14 的使用场景更多是在已有代码的优化和小修小补上。编译器支持:尽管大部分现代编译器支持 C++14,但早期的编译器可能对一些新特性的支持不完全,开发者在使用这些特性时需要确认编译器的兼容性。总结:
C++14 是 C++ 语言的一个小版本更新,主要通过增强和扩展 C++11 中的特性来提升语言的灵活性、可用性和安全性。它引入了泛型 Lambda、变量模板、std::make_unique
等重要特性,并修复了 C++11 中的一些边界问题。C++14 对于已经使用 C++11 的开发者来说是一个重要的改进,但它的变化相对较小,不会像 C++11 那样对整个语言体系造成颠覆性的影响。
8. C++ 2017: C++17
重要更新: 结构化绑定声明:允许通过auto [x, y] = pair
等语法,直接解构元组或结构体。**std::filesystem
**:引入文件系统库,提供跨平台的文件系统操作接口。if
和 switch
初始化:允许在 if
或 switch
语句中直接初始化变量。并行算法:STL 中的算法库支持并行执行,如并行排序。**std::optional
**:提供了一个容器,可以包含一个值或为空,用于避免空指针的使用。**std::variant
**:实现了类似于联合体的类型,但比 C 的 union
更安全和灵活。**改进的 std::any
**:增强了类型安全的通用容器,允许存储任意类型。 C++17(也被称为C++ 2017)是C++编程语言的一个重要版本,它在C++11和C++14的基础上进行了许多改进,增强了语言特性、库功能以及编译器支持。C++17的主要亮点包括:
1. 结构化绑定声明 (Structured Bindings)
C++17 引入了结构化绑定,允许你将一个结构或元组拆分为多个变量,从而让代码更加简洁易读。
示例:
#include <tuple>#include <iostream>std::tuple<int, double, std::string> getData() { return {1, 3.14, "Hello, C++17!"};}int main() { auto [x, y, z] = getData(); // 结构化绑定 std::cout << x << ", " << y << ", " << z << std::endl; return 0;}
输出:
1, 3.14, Hello, C++17!
2. if/else语句中的初始化语句 (If/else with initialization)
C++17允许在if
或else
语句中进行变量初始化,避免了冗余的变量声明。
示例:
#include <iostream>int main() { if (int x = 10; x > 5) { std::cout << "x is greater than 5" << std::endl; } else { std::cout << "x is not greater than 5" << std::endl; } return 0;}
输出:
x is greater than 5
注意:x
只在if
或else
的作用域内有效。
3. std::optional
std::optional
是一个模板类,用来表示一个可能为空的值。它可以用来避免使用空指针或特殊值来表示无效数据。
示例:
#include <iostream>#include <optional>std::optional<int> findValue(bool found) { if (found) { return 42; } else { return std::nullopt; // 返回空值 }}int main() { auto value = findValue(true); if (value) { std::cout << "Found value: " << *value << std::endl; } else { std::cout << "Value not found" << std::endl; } return 0;}
输出:
Found value: 42
4. std::string_view
std::string_view
是一个轻量级的字符串视图,避免了复制字符串数据,提供了对字符串的只读访问。
示例:
#include <iostream>#include <string_view>void printString(std::string_view str) { std::cout << str << std::endl;}int main() { std::string str = "Hello, C++17!"; printString(str); // 不会复制数据 return 0;}
输出:
Hello, C++17!
5. std::filesystem
C++17加入了对文件系统操作的标准库支持,std::filesystem
使得处理文件和目录变得更加方便。
示例:
<iostream> - C++ Reference
#include <iostream>#include <filesystem>namespace fs = std::filesystem;int main() { fs::path p = "example.txt"; if (fs::exists(p)) { std::cout << p << " exists!" << std::endl; } else { std::cout << p << " does not exist." << std::endl; } return 0;}
输出:
example.txt does not exist.
6. 并行算法 (Parallel Algorithms)
C++17添加了对并行执行算法的支持,例如使用 std::for_each
和其他标准算法的并行执行。
示例:
#include <iostream>#include <vector>#include <algorithm>#include <execution>int main() { std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9}; std::for_each(std::execution::par, data.begin(), data.end(), [](int& x) { x *= 2; }); for (int x : data) { std::cout << x << " "; } return 0;}
输出:
2 4 6 8 10 12 14 16 18
(注意:并行执行可能因环境不同而产生不同的输出顺序)
7. 内联变量 (Inline Variables)
C++17引入了内联变量,解决了头文件中静态变量带来的链接问题。
示例:
#include <iostream>inline int x = 42; // 内联变量int main() { std::cout << x << std::endl; return 0;}
8. 改进的constexpr
C++17扩展了constexpr
的功能,允许在编译时执行更多的操作,比如动态分配内存和使用if
语句。
示例:
#include <iostream>constexpr int factorial(int n) { return (n == 0) ? 1 : n * factorial(n - 1);}int main() { std::cout << "Factorial of 5: " << factorial(5) << std::endl; return 0;}
输出:
Factorial of 5: 120
总结
C++17引入了许多新特性,极大提高了语言的表达力和编程效率,尤其是在简化代码、提高性能和增加灵活性方面。对于现代C++开发者来说,熟练掌握这些特性将大大提升开发体验和代码质量。
9. C++ 2020: C++20
重大的新特性: 模块(Modules):引入了模块化的支持,替代传统的头文件和源文件方式,减少编译时间。协程(Coroutines):支持异步编程,简化了异步函数的编写。概念(Concepts):引入了模板约束,使得模板编程更加灵活和易于理解。范围(Ranges):增强了容器操作的灵活性和简洁性,提供了更强大的算法支持。**std::format
**:提供了类似 Python 中的格式化字符串功能,简化了输出。**consteval
和 constinit
**:新关键字,用于常量表达式和常量初始化的严格控制。**改进的 constexpr
**:支持更多的编译时功能,包括动态内存分配。 C++20 是 C++ 标准的一个重要更新,它在语言特性、库功能、并发支持等方面进行了大量的扩展和增强。C++20 对语言进行了重要的现代化,使得 C++ 更加高效、简洁、易用。以下是 C++20 中的一些主要特性及其代码示例:
1. 概念 (Concepts)
概念是 C++20 的一项新特性,用来约束模板类型。它允许我们更精确地控制模板参数类型,提供编译时检查和更好的错误信息。
示例:
#include <iostream>#include <concepts>template <typename T>concept Incrementable = requires(T a) { ++a; a++; };template <Incrementable T>T increment(T x) { return ++x;}int main() { int a = 5; std::cout << increment(a) << std::endl; // 正常工作 // std::string s = "Hello"; // std::cout << increment(s) << std::endl; // 编译错误,因为 std::string 不符合 Incrementable 概念 return 0;}
输出:
6
2. 范围 (Ranges)
C++20 引入了 std::ranges
,为标准库中的容器和算法提供了更加一致和方便的操作方法,支持通过管道操作符(|
)组合算法。
示例:
#include <iostream>#include <vector>#include <ranges>int main() { std::vector<int> nums = {1, 2, 3, 4, 5}; // 使用管道操作符对容器进行操作 auto result = nums | std::views::transform([](int x) { return x * 2; }) | std::views::filter([](int x) { return x > 5; }); for (int val : result) { std::cout << val << " "; } return 0;}
输出:
6 8 10
3. 协程 (Coroutines)
C++20 引入了协程支持,使得编写异步代码更加简洁。协程允许暂停和恢复函数的执行,适用于处理 I/O 操作或其他需要异步操作的场景。
示例:
#include <iostream>#include <coroutine>struct Task { struct promise_type; using handle_type = std::coroutine_handle<promise_type>; struct promise_type { Task get_return_object() { return Task{handle_type::from_promise(*this)}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void unhandled_exception() { std::exit(1); } void return_void() {} }; handle_type coro; Task(handle_type h) : coro(h) {} ~Task() { coro.destroy(); } void resume() { coro.resume(); }};Task simpleCoroutine() { std::cout << "Start of coroutine\n"; co_await std::suspend_always{}; std::cout << "End of coroutine\n";}int main() { auto coro = simpleCoroutine(); coro.resume(); // 启动协程 coro.resume(); // 恢复协程 return 0;}
输出:
Start of coroutineEnd of coroutine
4. 三向比较 (Spaceship Operator <=>
)
C++20 引入了“太空船操作符” (<=>
),也叫做三向比较操作符,它提供了一种简化的方式来执行比较操作,如 <
、<=
、==
、>
、>=
。
示例:
#include <iostream>struct Point { int x, y; auto operator<=>(const Point&) const = default; // 默认生成比较操作符};int main() { Point p1 = {1, 2}, p2 = {2, 3}; if (p1 < p2) { std::cout << "p1 is less than p2\n"; } return 0;}
输出:
p1 is less than p2
5. 模块 (Modules)
C++20 引入了模块的概念,这是对头文件的替代。模块可以提高编译速度,避免头文件带来的重复处理和依赖问题。模块支持 import
语句来替代传统的 #include
。
示例:
假设我们有一个模块 math
:
// math.cppm - 模块定义文件export module math;export int add(int a, int b) { return a + b; }
然后在主程序中导入该模块:
// main.cppimport math;int main() { int result = add(3, 4); std::cout << result << std::endl; // 输出 7 return 0;}
注意:模块在许多编译器中仍处于实验阶段,需要启用特定的编译器选项。
6. 范围循环 (Range-based for loop with initializer)
C++20 增强了范围 for 循环,允许在循环中初始化变量。
示例:
#include <iostream>#include <vector>int main() { std::vector<int> nums = {1, 2, 3, 4}; for (auto&& [index, value] : nums) { // 使用结构化绑定 std::cout << "Value: " << value << std::endl; } return 0;}
输出:
Value: 1Value: 2Value: 3Value: 4
7. std::span
std::span
是 C++20 新增的一个轻量级的视图容器,它可以用来表示一个数组的连续区间。它与传统的指针数组相比,更加安全,并支持对数组进行边界检查。
示例:
#include <iostream>#include <span>void printSpan(std::span<int> sp) { for (auto val : sp) { std::cout << val << " "; }}int main() { int arr[] = {1, 2, 3, 4, 5}; printSpan(arr); // 使用 std::span 传递数组 return 0;}
输出:
1 2 3 4 5
8. consteval
和 constinit
C++20 引入了 consteval
和 constinit
关键字:
consteval
用于指定一个函数必须在编译时求值。constinit
用于确保某个变量在初始化时是常量。 示例:
#include <iostream>consteval int square(int n) { return n * n; }int main() { constexpr int result = square(5); // 在编译时计算 std::cout << result << std::endl; // 输出 25 return 0;}
输出:
25
总结
C++20 引入了许多强大的新特性,极大增强了 C++ 的表达能力和编程效率。它使得编写更现代、更安全和更高效的 C++ 代码变得更加容易。例如,概念和协程提高了代码的可读性和可维护性,而模块的引入可以显著提高编译性能。掌握 C++20 的特性将有助于编写更清晰、强大和高效的 C++ 代码。
10. C++ 2023: C++23
新特性和小幅增强: **扩展的std::ranges
**:提供更多的支持与增强,使得 C++ 的标准库更具表达力和功能。 改进的协程支持:协程功能得到进一步加强,增加了更多的灵活性和优化。更好的标准化和规范:提高了 C++ 语言和标准库的易用性和性能。 C++23(正式名称为 C++23)是C++语言的最新标准,作为C++20和C++17之后的下一代标准,C++23在语言特性、库功能和编译器优化等方面引入了一些重要的改进。以下是C++23中的一些新特性和代码示例。
1. 改进的常量表达式(constexpr
)
C++23扩展了constexpr
的功能,允许更多复杂的功能在编译时执行。例如,C++23允许在constexpr
函数中使用try-catch
语句,这在之前的标准中是无法实现的。
示例:
constexpr int safe_divide(int a, int b) { if (b == 0) throw std::invalid_argument("Division by zero"); return a / b;}int main() { constexpr int result = safe_divide(10, 2); // 编译时执行 return 0;}
2. std::expected
C++23引入了std::expected
,它是一个可以用来表示函数调用结果的类型,类似于std::optional
,但是它包含了错误信息。这个特性非常适合替代try-catch
块来进行错误处理,尤其是在函数返回时希望包含更多的错误信息时。
示例:
#include <expected>#include <iostream>std::expected<int, std::string> divide(int a, int b) { if (b == 0) { return std::unexpected("Division by zero"); } return a / b;}int main() { auto result = divide(10, 0); if (result) { std::cout << "Result: " << *result << std::endl; } else { std::cout << "Error: " << result.error() << std::endl; } return 0;}
3. 范围(Ranges)库增强
C++20引入了范围(Ranges)库,C++23在此基础上进行了增强。新增了更丰富的算法和视图,使得在进行集合操作时,代码更加简洁且易于理解。
示例:
#include <ranges>#include <vector>#include <iostream>int main() { std::vector<int> v = {1, 2, 3, 4, 5}; // 使用ranges库处理集合 auto result = v | std::views::transform([](int n) { return n * n; }) | std::views::filter([](int n) { return n > 10; }); for (int i : result) { std::cout << i << " "; } return 0;}
4. std::format
改进
C++20引入了 std::format
来格式化字符串,C++23对其进行了进一步改进。新增了更多的格式化选项,以及对各种类型的支持。
示例:
#include <format>#include <iostream>int main() { int age = 25; std::string name = "Alice"; std::string formatted = std::format("Name: {}, Age: {}", name, age); std::cout << formatted << std::endl; return 0;}
5. explicit
改进
C++23扩展了explicit
关键字,可以用于更加灵活的构造函数,使其适应更复杂的类型转换需求。
示例:
struct A { explicit A(int x) {} // 显式构造函数};struct B { explicit B(A a) {} // 显式构造函数};int main() { A a(1); B b(a); // 需要显示构造A对象的参数 return 0;}
6. std::span
支持的改进
std::span
是C++20中引入的用于表示数组片段的类,C++23对其进行了扩展,支持了更多的功能。
示例:
#include <span>#include <iostream>void print_span(std::span<int> s) { for (auto elem : s) { std::cout << elem << " "; }}int main() { int arr[] = {1, 2, 3, 4, 5}; std::span<int> sp(arr, 3); // 只传递数组的前3个元素 print_span(sp); return 0;}
7. 新的属性([[likely]]
和 [[unlikely]]
)
C++23引入了 [[likely]]
和 [[unlikely]]
属性,用于给编译器提供分支预测的提示,帮助优化代码。
示例:
#include <iostream>int main() { bool condition = true; if ([[likely]] condition) { std::cout << "Condition is likely true" << std::endl; } else { std::cout << "Condition is unlikely true" << std::endl; } return 0;}
总结
C++23增强了语言的表达能力和效率,提供了更多的编程便利性,尤其在常量表达式、错误处理、范围操作、字符串格式化和编译时优化方面有显著的提升。这些特性使得C++更加现代化,代码更加简洁易懂,同时也带来了更高效的执行性能。
这些新特性和API增强为开发者提供了更加灵活和强大的工具,可以让代码更加高效、易维护并且更具可读性。