C++ 的发展

目录

[C++ 的发展总结:​编辑](#C++ 的发展总结:编辑)

[1. C++ 的早期发展(1979-1985)](#1. C++ 的早期发展(1979-1985))

[2. C++ 标准化过程(1985-1998)](#2. C++ 标准化过程(1985-1998))

[3. C++ 标准演化(2003-2011)](#3. C++ 标准演化(2003-2011))

[4. C++11(2011年)](#4. C++11(2011年))

[5. C++14(2014年)](#5. C++14(2014年))

[6. C++17(2017年)](#6. C++17(2017年))

[7. C++20(2020年)](#7. C++20(2020年))

[8. C++23(2023年)](#8. C++23(2023年))

[1. C++ 1985: C++ 1.0](#1. C++ 1985: C++ 1.0)

主要特性:

示例代码:

代码讲解:

[C++ 1.0 的局限性:](#C++ 1.0 的局限性:)

总结:

[2. C++ 1989: C++ 2.0](#2. C++ 1989: C++ 2.0)

主要特性:

多重继承与虚继承

示例代码:

代码讲解:

运行输出:

解释:

[C++ 2.0 的局限性:](#C++ 2.0 的局限性:)

总结:

[3. C++ 1990: C++ 3.0](#3. C++ 1990: C++ 3.0)

主要特性:

模板的引入

示例代码:模板示例

代码讲解:

运行输出:

代码解释:

模板的优势:

[C++ 3.0 的局限性:](#C++ 3.0 的局限性:)

总结:

[4. C++ 1998: C++98](#4. C++ 1998: C++98)

主要特性:

[示例代码:C++98 的常见特性](#示例代码:C++98 的常见特性)

代码讲解:

运行输出:

代码解释:

[C++98 的局限性:](#C++98 的局限性:)

总结:

[5. C++ 2003: C++03](#5. C++ 2003: C++03)

主要特性和变化:

[C++03 与 C++98 的区别:](#C++03 与 C++98 的区别:)

[示例代码:C++98 和 C++03 的差异](#示例代码:C++98 和 C++03 的差异)

[示例代码:模板特化修复和 SFINAE 改进](#示例代码:模板特化修复和 SFINAE 改进)

代码解释:

运行输出:

[C++03 与 C++98 的局限性:](#C++03 与 C++98 的局限性:)

总结:

[6. C++ 2011: C++11](#6. C++ 2011: C++11)

主要新特性:

[示例代码:C++11 特性](#示例代码:C++11 特性)

代码解释:

运行输出:

[C++11 的优势:](#C++11 的优势:)

[C++11 的局限性:](#C++11 的局限性:)

总结:

[7. C++ 2014: C++14](#7. C++ 2014: C++14)

主要新特性:

[示例代码:C++14 新特性](#示例代码:C++14 新特性)

代码解释:

运行输出:

[C++14 的优势:](#C++14 的优势:)

[C++14 的局限性:](#C++14 的局限性:)

总结:

[8. C++ 2017: C++17](#8. C++ 2017: C++17)

[1. 结构化绑定声明 (Structured Bindings)](#1. 结构化绑定声明 (Structured Bindings))

示例:

[2. if/else语句中的初始化语句 (If/else with initialization)](#2. if/else语句中的初始化语句 (If/else with initialization))

示例:

[3. std::optional](#3. std::optional)

示例:

[4. std::string_view](#4. std::string_view)

示例:

[5. std::filesystem](#5. std::filesystem)

示例:

[6. 并行算法 (Parallel Algorithms)](#6. 并行算法 (Parallel Algorithms))

示例:

[7. 内联变量 (Inline Variables)](#7. 内联变量 (Inline Variables))

示例:

[8. 改进的constexpr](#8. 改进的constexpr)

示例:

总结

[9. C++ 2020: C++20](#9. C++ 2020: C++20)

[1. 概念 (Concepts)](#1. 概念 (Concepts))

示例:

[2. 范围 (Ranges)](#2. 范围 (Ranges))

示例:

[3. 协程 (Coroutines)](#3. 协程 (Coroutines))

示例:

[4. 三向比较 (Spaceship Operator <=>)](#4. 三向比较 (Spaceship Operator <=>))

示例:

[5. 模块 (Modules)](#5. 模块 (Modules))

示例:

[6. 范围循环 (Range-based for loop with initializer)](#6. 范围循环 (Range-based for loop with initializer))

示例:

[7. std::span](#7. std::span)

示例:

[8. consteval 和 constinit](#8. consteval 和 constinit)

示例:

总结

[10. C++ 2023: C++23](#10. C++ 2023: C++23)

[1. 改进的常量表达式(constexpr)](#1. 改进的常量表达式(constexpr))

示例:

[2. std::expected](#2. std::expected)

示例:

[3. 范围(Ranges)库增强](#3. 范围(Ranges)库增强)

示例:

[4. std::format 改进](#4. std::format 改进)

示例:

[5. explicit 改进](#5. explicit 改进)

示例:

[6. std::span 支持的改进](#6. std::span 支持的改进)

示例:

[7. 新的属性([[likely]] 和 [[unlikely]])](#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_ptrstd::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;);
    • ifswitch 中的初始化语句
    • **std::filesystem**:用于处理文件和目录的标准库;
    • **改进的 std::stringstd::array**;
    • 并行算法std::for_each 等支持并行执行)。
  • C++17 不仅增强了语言本身的功能,还进一步加强了对现代硬件和多核处理器的支持,增强了性能和并行计算能力。

7. C++20(2020年)

  • 2020年 :C++20 发布,是 C++ 语言历史上一个非常重要的版本,带来了许多令人兴奋的新特性:
    • 模块(Modules):改善头文件管理,减少编译时间;
    • 三方比较操作符<=>): 用于自动生成比较操作符(比如 ==, !=, <, <=, >, >=);
    • 协程(Coroutines):使得异步编程更加简洁;
    • 概念(Concepts):提供更强的类型约束机制,使模板编程更加安全;
    • 范围 for 循环改进:更简洁的语法和强大的灵活性;
    • **std::span**:处理数组和内存块的轻量级对象;
    • 改进的标准库 :包括 std::formatstd::rangesstd::calendar 等。
  • C++20 为 C++ 带来了大量的现代化特性,并进一步提升了语言的表达能力、性能和并发编程的支持。

8. C++23(2023年)

  • 2023年 :C++23 发布,虽然其变化相较于 C++20 比较平稳,但仍然包含了一些重要的改进和修复:
    • 新的标准库功能 :例如,std::expectedstd::generatorstd::ranges 的进一步改进;
    • 语言增强:对模板和类型推导的改进,增强了语言的灵活性和可读性;
    • 性能优化:进一步增强编译器对并行、异步和内存管理的支持。
  • C++23 标志着 C++ 语言持续向现代化发展,并且对性能和并发编程的支持进一步加强。
  1. 从面向过程到面向对象:最初的 C++ 语言只是在 C 语言的基础上增加了类和面向对象的特性,经过多年发展,C++ 在保留 C 语言高效性的同时,也吸收了面向对象、泛型编程和函数式编程的优势,成为了一门多范式的语言。

  2. 标准化过程:从 C++98 到 C++11,再到 C++14、C++17 和 C++20,C++ 逐渐成为一种具有广泛应用的编程语言,每个版本都带来了一些新的特性和增强,逐步适应现代软件开发的需求。

  3. 现代化与性能: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++ 标准奠定了基础。

主要特性:
  1. 类与对象:C++ 1.0 引入了面向对象编程的核心概念,最初的类和对象支持比较简单。

    • 类是 C++ 中的基本构造,用于封装数据和功能。
    • 对象是类的实例,表示实际的数据和行为。
  2. 函数和运算符重载:C++ 1.0 支持函数重载和运算符重载,使得程序员可以根据需要定义不同版本的函数或操作符。

  3. 基本继承:C++ 1.0 支持从一个类继承另一个类,使得可以构建更为复杂的类结构。

  4. 无标准库:当时的 C++ 语言没有像现代 C++ 那样的标准库。数据结构和算法通常依赖开发者自己编写。

示例代码:

C++ 1.0 版本的代码相对简单。以下是一个典型的 C++ 1.0 示例,演示了类的定义、对象创建、继承以及运算符重载。

cpp 复制代码
#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**:定义了一个包含 lengthbreadthheight 的类,用于表示一个盒子,并且提供了一个计算体积的方法 volume()
  • 构造函数 :用于初始化 Box 对象,设置它的长度、宽度和高度。
  • 运算符重载 :使用 operator+ 重载运算符 +,使得两个 Box 对象相加时,返回一个新的 Box 对象,长度、宽度和高度分别相加。
  • main() 中创建对象 :通过构造函数创建了 box1box2,并计算它们的体积。在计算 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++ 语言标准奠定了许多重要基础。

主要特性:
  1. 多重继承:C++ 2.0 引入了多重继承的支持,使得一个类可以继承多个基类,从而可以组合多个类的功能。
  2. 虚继承 :为了解决多重继承带来的"菱形继承"问题(即一个类通过多个继承路径继承同一个基类),C++ 2.0 引入了 虚继承 的概念。虚继承确保通过多个继承路径继承的同一个基类只有一份副本。
  3. 虚函数 :继续扩展了对面向对象编程的支持,尤其是通过 虚函数 机制,使得 C++ 支持 运行时多态
  4. 更强的类型检查:C++ 2.0 对类型检查进行了增强,使得语言的类型系统更加严格和安全。

多重继承与虚继承

C++ 2.0 的最大变化之一就是支持 多重继承 ,并且引入了 虚继承 来解决多重继承可能引起的问题。在多重继承中,如果一个类继承自多个基类,并且这些基类有公共的祖先类,那么在派生类中会有重复的祖先类副本,这时就可能出现问题。虚继承解决了这一问题,通过确保只有一个祖先类副本,从而避免了数据冗余和潜在的错误。

示例代码:

以下是一个简单的示例,演示了 多重继承虚继承 的概念。

cpp 复制代码
#include <iostream>
using namespace std;

// 基类A
class A {
public:
    A() { cout << "Class A constructor" << endl; }
    void showA() { cout << "Class A" << endl; }
};

// 基类B
class B {
public:
    B() { cout << "Class B constructor" << endl; }
    void showB() { cout << "Class B" << endl; }
};

// 基类C,虚继承A
class C : virtual public A {
public:
    C() { cout << "Class C constructor" << endl; }
    void showC() { cout << "Class C" << endl; }
};

// 派生类D,虚继承A和B
class 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 和 BAB 是两个基类,都有自己的构造函数和成员函数。A 有一个 showA() 函数,B 有一个 showB() 函数。
  • 类 CC 类继承了 A 类,并使用 virtual 关键字进行 虚继承 。这样,在 C 的子类中,如果有多个继承自 A 的路径,它们会共享同一个 A 类副本,避免了重复数据。
  • 类 DD 类从 CB 继承,并且通过虚继承机制共享了 A 类的副本。
  • 输出
    • D 类的对象被创建时,首先调用 ABC 的构造函数,再调用 D 的构造函数。
    • showA()showB()showC() 分别调用了从基类继承的成员函数。

运行输出:

cpp 复制代码
Class A constructor
Class B constructor
Class C constructor
Class D constructor
Class A
Class B
Class C
Class D

解释:

  • 虚继承C 类通过 virtual public A 虚继承了 A 类,保证了通过 D 类的继承关系,A 类只有一份副本。即使 D 类是通过 BC 两个路径继承 AA 类也只会被构造一次。
  • 多重继承D 类通过多重继承继承了 BC,因此 D 类拥有 BC 类的功能。

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++ 支持编写与类型无关的代码,从而使得编程变得更加灵活和强大。

主要特性:
  1. 模板(Templates)

    • 函数模板:允许定义可以接受不同类型参数的函数。
    • 类模板:允许定义可以接受不同类型参数的类。模板是 C++ 语言中泛型编程的基础。
  2. 增强的类型系统

    • 支持更复杂的类型定义和类型推导。
    • 改进了类和对象的类型推断机制。
  3. 基本的标准库(STL的雏形)

    • 尽管 C++ 3.0 本身并没有正式定义标准模板库(STL),但它开始支持类似 STL 的一些容器和算法概念,为未来 STL 的引入奠定了基础。
  4. 支持虚函数、运算符重载等特性

    • C++ 3.0 继续扩展了面向对象编程的支持,增强了对继承、多态、运算符重载等特性的支持。

模板的引入

C++ 3.0 的核心改进就是引入了模板机制,使得函数和类能够接受参数类型作为模板参数。这使得 C++ 能够支持泛型编程,从而能够编写类型安全且重用性更高的代码。

示例代码:模板示例

以下是一个简单的示例,展示了如何在 C++ 3.0 中使用 函数模板类模板

cpp 复制代码
#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 是一个类型参数,可以是任何数据类型(如 intdouble 等),当调用模板函数时,编译器会根据传入的参数类型推导出 T 的具体类型。
  • **类模板 Box**:

    • Box 是一个类模板,它有一个类型为 T 的成员变量 value
    • 构造函数接受一个 T 类型的参数来初始化 value,并提供了 getValuesetValue 方法来访问和修改 value

运行输出:

cpp 复制代码
Max of x and y: 20
Max of a and b: 3.14
Box contains: 100
Updated Box contains: 200
Box contains: 3.14159

代码解释:

  • getMax 函数模板 :在 main() 中,分别使用了 intdouble 类型的参数来调用 getMax 函数模板。编译器根据传入的参数类型推导出 T 的类型。
  • Box 类模板Box<int>Box<double> 分别是使用 intdouble 类型的类模板实例化出来的对象。每个 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(标准模板库) :引入了标准模板库,包括 vectorlistmapset 等容器,及算法(如排序、查找等)。map - C++ Reference set - C++ Reference
    • 命名空间(namespace):为了避免名称冲突,引入了命名空间。
    • 异常处理 :引入了 trycatchthrow 异常处理机制。
    • RTTI(运行时类型信息) :引入了 typeiddynamic_cast,允许运行时识别对象的类型。

C++98 是 C++ 语言的第一个国际标准,正式由 ISO(国际标准化组织)在 1998 年发布。C++98 语言标准继承了 C++ 3.0 的核心特性,并在此基础上进行了多个重要的改进和规范化。这个版本的 C++ 为标准库(STL)提供了规范,并开始支持更多的现代编程特性。

主要特性:
  1. 模板

    • C++98 中的模板特性得到了进一步的增强,支持函数模板和类模板,并且模板的使用变得更加广泛。模板参数可以是类、函数、指针等类型。
  2. 标准模板库(STL)

sort - C++ Reference

  1. 异常处理

    • C++98 提供了标准化的异常处理机制,使用 try, catch, throw 语句来处理运行时错误。
  2. 命名空间

    • C++98 引入了 命名空间namespace),用于避免名称冲突,尤其是在大型项目中。
  3. 虚函数与多态

    • C++98 继续强化了面向对象编程的支持,特别是对 虚函数多态 的使用。
  4. const 和引用

    • C++98 对 const 关键字和引用进行了严格的规范,使得编程更加安全。
  5. 函数指针和类型转换

    • 提供了对 函数指针类型转换 (如 static_cast, dynamic_cast 等)的支持,增强了 C++ 的灵活性。
  6. 类成员的类型推导

    • C++98 引入了对类成员类型的推导,允许在某些情况下省略类型声明。
示例代码:C++98 的常见特性

以下是一个综合示例,展示了 C++98 中的几个核心特性,包括模板、标准库(STL)、命名空间和异常处理。

vector - C++ Reference

cpp 复制代码
#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 块中捕获它,输出异常的描述信息。

运行输出:

cpp 复制代码
Max of x and y: 20
Sorted vector: 1 1 2 3 3 4 5 5 5 6 9 
Caught exception: Index out of range!

代码解释:

  1. **模板 getMax**:通过模板,可以在运行时自动确定 T 的类型,支持不同的数据类型(如 intdouble 等)。在本例中,它比较了两个整数 xy
  2. **STL 容器 std::vectorstd::sort**:std::vector 是一个可以动态调整大小的容器,它存储一系列元素。std::sort 是一个通用算法,用来对容器中的元素进行排序。
  3. 异常处理:C++98 提供了标准的异常处理机制,允许在代码运行过程中抛出和捕获异常,避免程序因错误而崩溃。

C++98 的局限性:

  1. 没有 auto 关键字 :C++98 中没有 auto 关键字,因此类型推导只能依靠显式的类型声明。
  2. **没有 nullptr**:C++98 中没有 nullptr,指针使用时可能会引发隐式的类型转换问题。
  3. 没有类型推导的 for 循环 :C++98 中没有像 C++11 中那样的基于范围的 for 循环(for (auto& elem : container))。
  4. 模板元编程有限:虽然模板功能在 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)等方面的细节修正,确保了编译器能够更好地支持标准库。

主要特性和变化:

  1. 模板的修正和改进

    • C++03 对模板特化和模板元编程做了小的修正,使得编译器对模板的支持更加一致。
    • 改进了模板在某些边界情况中的行为,避免了 C++98 中一些不一致或令人困惑的部分。
  2. 标准库的修正

    • C++03 对标准库中的一些接口做了微调,解决了 C++98 标准库中的一些小问题。例如,修复了 std::vector 在某些情况下的行为不一致性,确保了 STL 中的算法与容器的更好兼容性。
  3. 修复了常见的编译器问题

    • C++03 对一些编译器的兼容性问题进行了修复,确保不同厂商的编译器之间有更好的兼容性。
  4. 去除了某些不再使用的特性

    • 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 改进
cpp 复制代码
#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>::type
printType(const T& value) {
    std::cout << "Non-integer value: " << value << std::endl;
}

template <typename T>
typename std::enable_if<std::is_integral<T>::value, void>::type
printType(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;
}

代码解释:

  1. 模板类 Printer 的特化

    • Printer 是一个模板类,在默认情况下,它的 print 函数打印任意类型的值。
    • 特化版本 Printer<const T>const 类型的处理进行了特殊化,使其输出时带有 "const value: " 字样。此特化是在 C++03 中明确规定的,确保了特化行为的统一性。
  2. SFINAE(Substitution Failure Is Not An Error)

    • printType 函数使用了 SFINAE 来根据类型 T 的不同选择不同的版本。

    • 使用 std::enable_ifstd::is_integral 来判断 T 是否为整数类型,并分别调用不同的函数。SFINAE 机制可以避免无效的模板实例化,确保了代码的类型安全。

    • 如果 T 是整数类型,printType(int) 会被调用;否则,printType(double) 会被调用。

运行输出:

cpp 复制代码
123
const value: 456
Integer value: 123
Non-integer value: 3.14

C++03 与 C++98 的局限性:

  1. 没有新的语言特性:C++03 仅仅是 C++98 的修正版本,没有引入新的语言特性。开发者并未从中获得像 C++11、C++14、C++17 那样的重大进展。
  2. 标准库的改进有限:虽然 C++03 修复了一些标准库的问题,但与后来的 C++ 标准相比,它的功能仍显得较为简单。
  3. 没有现代化工具 :如 autonullptr、范围 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_ptrstd::shared_ptrstd::weak_ptr,用于自动管理内存,避免内存泄漏。
    • Lambda 表达式:允许定义匿名函数,可以在代码中更方便地使用函数对象。
    • 并发支持:引入了 <thread> 库,允许多线程编程。
    • **nullptr**:引入了 nullptr 关键字,替代 NULL,提高代码的类型安全。
    • 右值引用和移动语义:引入右值引用(&&)和 std::move,提高对象传递效率,减少不必要的拷贝。
    • 范围 for 循环:引入了简洁的范围 for 循环,简化容器遍历。
    • 类型别名(using):引入 using 关键字,简化类型别名定义。
    • 变长模板(Variadic Templates):支持可变参数模板,提高模板的灵活性。

C++11 是 C++ 语言的一个重大更新,正式于 2011 年发布。它引入了大量新的特性和改进,使 C++ 语言更现代化、更加高效和易于使用。C++11 标准的推出,极大地扩展了 C++ 的功能,使得 C++ 开发变得更加灵活、简洁,同时还提升了性能。

主要新特性:

  1. 自动类型推导(auto

    • auto 关键字允许编译器根据表达式的类型自动推导变量的类型,减少了类型声明的冗余,提高了代码可读性。
  2. 右值引用与移动语义(&&std::move

    • 引入右值引用(&&)和 std::move,实现了 移动语义。通过移动资源而不是复制,显著提高了效率,尤其在需要大量数据传输的场合(如容器操作)。
  3. 范围 for 循环

    • 引入了范围 for 循环(range-based for loop),简化了容器元素的遍历,避免了传统迭代器的复杂性。
  4. Lambda 表达式

    • Lambda 表达式允许在函数内定义匿名函数,并且可以捕获外部变量,极大地增强了函数式编程的支持。
  5. **nullptr**:

    • nullptr 替代了 NULL,它是一个类型安全的空指针常量,消除了 NULL 的类型不匹配问题。
  6. **constexpr**:

    • constexpr 使得可以在编译时求值的常量表达式更加简洁,增强了编译期计算的能力。
  7. 并发编程:<thread>

    • C++11 引入了原生的线程支持,<thread> 库使得多线程编程变得更加容易和高效。
  8. 类型别名(using

    • using 关键字可以用来为类型定义别名,取代了传统的 typedef,语法更加简洁。
  9. 强类型枚举(enum class

    • 引入了强类型枚举 enum class,避免了传统枚举可能产生的隐式转换和命名冲突问题。
  10. **新标准库:std::chrono**:

    • C++11 引入了用于处理时间和日期的新标准库 std::chrono,使得处理时间变得更加直观和精确。

示例代码:C++11 特性

下面的代码示例展示了 C++11 的一些关键特性。

cpp 复制代码
#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;
}

代码解释:

  1. **自动类型推导 (auto)**:

    • 使用 auto 关键字,编译器会自动推导变量 xy 的类型,简化了类型声明,特别是对于复杂类型(如迭代器和函数返回类型)时非常有用。
  2. 范围 for 循环

    • 使用 C++11 引入的范围 for 循环来遍历容器。这个语法简洁、直观,避免了显式的迭代器操作。
  3. Lambda 表达式

    • 使用 std::for_each 算法与 lambda 表达式结合,计算容器中所有元素的总和。lambda 表达式 [&sum](int num) { sum += num; } 捕获外部变量 sum 并对容器中的每个元素执行加法操作。
  4. 右值引用与移动语义

    • moveExample 中,通过 std::move 实现了对象 a 的移动,将其资源转移给对象 b,触发了移动构造函数而不是拷贝构造函数。
  5. 线程支持

    • 使用 C++11 的 <thread> 库创建和启动一个线程,并且通过 join() 等待线程执行完成。std::thread 简化了多线程编程。

运行输出:

cpp 复制代码
x: 10, y: 3.14
Doubled values: 2 4 6 8 10
Sum of elements: 15
Move Constructor
Hello 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 的边界情况,增强编译器的支持,并提供一些性能上的提升。

主要新特性:

  1. 泛型 Lambda 表达式

    • C++14 扩展了 C++11 中的 Lambda 表达式,引入了泛型 Lambda,使得 Lambda 可以接受不同类型的参数而不需要显式地指定类型。
  2. 变量模板

    • C++14 引入了 变量模板,允许创建像模板函数一样的模板变量。之前只有函数和类可以是模板,但 C++14 使得变量也可以具有模板特性。
  3. Lambda 表达式的返回类型推导

    • 在 C++14 中,Lambda 表达式可以通过 auto 关键字自动推导返回类型。这避免了在 Lambda 表达式中手动指定返回类型的需要。
  4. **std::make_unique**:

    • 引入了 std::make_unique,作为 std::make_shared 的对称操作,它简化了对 std::unique_ptr 的创建,避免了不必要的 new 运算符。
  5. **decltype(auto)**:

    • 引入了 decltype(auto) 作为函数返回类型的推导方式,它可以推导出具有精确类型的返回值,支持返回引用类型的自动推导。
  6. 标准库改进

    • C++14 修复了 C++11 标准库中的一些问题,并改进了对各种常见编译器的支持。标准库中对线程、智能指针、算法等的支持变得更加稳定和高效。
  7. 二进制字面量

    • C++14 引入了二进制字面量(0b0B)的支持,使得表示二进制数更加直观。
  8. **std::exchange**:

    • 新增了 std::exchange 函数,它可以简化交换操作,尤其是当你需要交换一个对象并返回其原值时。

示例代码:C++14 新特性

以下代码展示了 C++14 中的一些关键特性,包括泛型 Lambda、变量模板、decltype(auto)std::make_unique 等。

cpp 复制代码
#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_unique
void 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::exchange
int 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;
}

代码解释:

  1. 泛型 Lambda 表达式

    • 通过 auto 来声明 Lambda 表达式的参数类型,使得 Lambda 可以接受任意类型的参数。这使得 Lambda 表达式更加灵活,可以应用于多种不同的类型。
  2. 变量模板

    • pi 是一个模板变量,它接受一个类型参数 T,并为每个类型提供不同的常量值。在 variableTemplate() 中,演示了如何使用模板变量来获取 pi 的不同类型值。
  3. Lambda 返回类型推导

    • 使用 auto 关键字,Lambda 表达式会自动推导返回类型。在 lambdaReturnType() 中,返回类型是乘积结果的类型,auto 会自动推导出其正确类型。
  4. **std::make_unique**:

    • std::make_unique 用于创建 std::unique_ptr,这是一个智能指针,用于管理动态分配的内存。std::make_unique 是 C++14 引入的,它比直接使用 new 更加安全和方便。
  5. **decltype(auto)**:

    • decltype(auto) 用于推导函数的返回类型,并且支持返回值是引用的情况。在 decltypeAuto() 中,returnRvalue() 返回一个右值引用,通过 decltype(auto) 可以正确地推导出返回类型。
  6. **std::exchange**:

    • std::exchange 是 C++14 引入的一个小工具,它用于交换一个变量的值并返回旧值。在 exchangeExample() 中,std::exchange 用于交换 value 的值并返回交换前的值。

运行输出:

cpp 复制代码
Sum of 3 and 4.5: 7.5
Pi as float: 3.14159
Pi as double: 3.14159
Multiply 4 and 5.5: 22
First element in unique_ptr array: 10
Rvalue returned: 5
Old value: 10, New value: 11

C++14 的优势:

  • 增强的类型推导 :通过 autodecltype(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**:引入文件系统库,提供跨平台的文件系统操作接口。
    • ifswitch 初始化:允许在 ifswitch 语句中直接初始化变量。
    • 并行算法: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 引入了结构化绑定,允许你将一个结构或元组拆分为多个变量,从而让代码更加简洁易读。

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
1, 3.14, Hello, C++17!

2. if/else语句中的初始化语句 (If/else with initialization)

C++17允许在ifelse语句中进行变量初始化,避免了冗余的变量声明。

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
x is greater than 5

注意:x只在ifelse的作用域内有效。

3. std::optional

std::optional 是一个模板类,用来表示一个可能为空的值。它可以用来避免使用空指针或特殊值来表示无效数据。

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
Found value: 42

4. std::string_view

std::string_view是一个轻量级的字符串视图,避免了复制字符串数据,提供了对字符串的只读访问。

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
Hello, C++17!

5. std::filesystem

C++17加入了对文件系统操作的标准库支持,std::filesystem使得处理文件和目录变得更加方便。

示例:

<iostream> - C++ Reference

cpp 复制代码
#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;
}

输出:

cpp 复制代码
example.txt does not exist.

6. 并行算法 (Parallel Algorithms)

C++17添加了对并行执行算法的支持,例如使用 std::for_each 和其他标准算法的并行执行。

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
2 4 6 8 10 12 14 16 18 

(注意:并行执行可能因环境不同而产生不同的输出顺序)

7. 内联变量 (Inline Variables)

C++17引入了内联变量,解决了头文件中静态变量带来的链接问题。

示例:
cpp 复制代码
#include <iostream>

inline int x = 42;  // 内联变量

int main() {
    std::cout << x << std::endl;
    return 0;
}

8. 改进的constexpr

C++17扩展了constexpr的功能,允许在编译时执行更多的操作,比如动态分配内存和使用if语句。

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
Factorial of 5: 120

总结

C++17引入了许多新特性,极大提高了语言的表达力和编程效率,尤其是在简化代码、提高性能和增加灵活性方面。对于现代C++开发者来说,熟练掌握这些特性将大大提升开发体验和代码质量。

9. C++ 2020: C++20

  • 重大的新特性:
    • 模块(Modules):引入了模块化的支持,替代传统的头文件和源文件方式,减少编译时间。
    • 协程(Coroutines):支持异步编程,简化了异步函数的编写。
    • 概念(Concepts):引入了模板约束,使得模板编程更加灵活和易于理解。
    • 范围(Ranges):增强了容器操作的灵活性和简洁性,提供了更强大的算法支持。
    • **std::format**:提供了类似 Python 中的格式化字符串功能,简化了输出。
    • **constevalconstinit**:新关键字,用于常量表达式和常量初始化的严格控制。
    • **改进的 constexpr**:支持更多的编译时功能,包括动态内存分配。

C++20 是 C++ 标准的一个重要更新,它在语言特性、库功能、并发支持等方面进行了大量的扩展和增强。C++20 对语言进行了重要的现代化,使得 C++ 更加高效、简洁、易用。以下是 C++20 中的一些主要特性及其代码示例:

1. 概念 (Concepts)

概念是 C++20 的一项新特性,用来约束模板类型。它允许我们更精确地控制模板参数类型,提供编译时检查和更好的错误信息。

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
6

2. 范围 (Ranges)

C++20 引入了 std::ranges,为标准库中的容器和算法提供了更加一致和方便的操作方法,支持通过管道操作符(|)组合算法。

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
6 8 10

3. 协程 (Coroutines)

C++20 引入了协程支持,使得编写异步代码更加简洁。协程允许暂停和恢复函数的执行,适用于处理 I/O 操作或其他需要异步操作的场景。

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
Start of coroutine
End of coroutine

4. 三向比较 (Spaceship Operator <=>)

C++20 引入了"太空船操作符" (<=>),也叫做三向比较操作符,它提供了一种简化的方式来执行比较操作,如 <<===>>=

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
p1 is less than p2

5. 模块 (Modules)

C++20 引入了模块的概念,这是对头文件的替代。模块可以提高编译速度,避免头文件带来的重复处理和依赖问题。模块支持 import 语句来替代传统的 #include

示例:

假设我们有一个模块 math

cpp 复制代码
// math.cppm - 模块定义文件
export module math;
export int add(int a, int b) { return a + b; }

然后在主程序中导入该模块:

cpp 复制代码
// main.cpp
import 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 循环,允许在循环中初始化变量。

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
Value: 1
Value: 2
Value: 3
Value: 4

7. std::span

std::span 是 C++20 新增的一个轻量级的视图容器,它可以用来表示一个数组的连续区间。它与传统的指针数组相比,更加安全,并支持对数组进行边界检查。

示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
1 2 3 4 5 

8. constevalconstinit

C++20 引入了 constevalconstinit 关键字:

  • consteval 用于指定一个函数必须在编译时求值。
  • constinit 用于确保某个变量在初始化时是常量。
示例:
cpp 复制代码
#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;
}

输出:

cpp 复制代码
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语句,这在之前的标准中是无法实现的。

示例:
cpp 复制代码
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块来进行错误处理,尤其是在函数返回时希望包含更多的错误信息时。

示例:
cpp 复制代码
#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在此基础上进行了增强。新增了更丰富的算法和视图,使得在进行集合操作时,代码更加简洁且易于理解。

示例:
cpp 复制代码
#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对其进行了进一步改进。新增了更多的格式化选项,以及对各种类型的支持。

示例:
cpp 复制代码
#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关键字,可以用于更加灵活的构造函数,使其适应更复杂的类型转换需求。

示例:
cpp 复制代码
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对其进行了扩展,支持了更多的功能。

示例:
cpp 复制代码
#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]] 属性,用于给编译器提供分支预测的提示,帮助优化代码。

示例:
cpp 复制代码
#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增强为开发者提供了更加灵活和强大的工具,可以让代码更加高效、易维护并且更具可读性。

相关推荐
重生之我是数学王子17 分钟前
QT 实现仿制 网络调试器(未实现连接唯一性) QT5.12.3环境 C++实现
开发语言·c++·qt
极地星光32 分钟前
C++自动化测试:GTest 与 GitLab CI/CD 的完美融合
c++·ci/cd·gitlab
St_Ludwig32 分钟前
蓝桥杯疑似例题解答方案(打印任意阶杨辉三角)
c语言·c++·后端·算法·职场和发展·蓝桥杯
枫の准大一44 分钟前
C++从零到满绩——类和对象(中)
开发语言·c++
9毫米的幻想1 小时前
【Linux系统】—— 基本指令(三)
linux·c语言·c++·学习
大白的编程日记.1 小时前
【C++笔记】数据结构进阶之二叉搜索树(BSTree)
开发语言·数据结构·c++·笔记
心.c1 小时前
0-1背包问题
c++·算法
小柯J桑_1 小时前
C++:用红黑树封装map与set-1
开发语言·c++·set·map·红黑树
熬夜学编程的小王1 小时前
【C++篇】从售票窗口到算法核心:C++队列模拟全解析
数据结构·c++·双端队列·队列·queue
gma9991 小时前
ES 基本使用与二次封装
大数据·数据库·c++·elasticsearch·搜索引擎