突破编程_C++_C++14新特性(C++14新特性概览)

1 C++14 的发展背景

C++14 是 C++ 编程语言的一个重要版本,它的发展背景紧密关联于C++语言的发展历程以及计算机科学领域的整体进步。

首先,C++ 语言起源于 20 世纪 80 年代早期,它的设计初衷是为了提供一种功能强大、高效且可移植的编程语言,以满足操作系统和底层系统软件的需求。C++ 语言在发展过程中,借鉴了早期的编程语言B,并对其进行了扩展和改进,最终成为了开发操作系统、编写嵌入式系统、编译器和其他系统软件的首选语言。

随着时间的推移,C++ 语言不断发展和完善,经历了多个版本的迭代。其中,C++11 是 C++ 语言发展中的一个重要里程碑,它引入了大量的新特性和改进,使得 C++ 语言更加现代化和高效。然而,C++11 仍然存在一些遗留问题和需要改进的地方。

在这样的背景下,C++14 应运而生。C++14 的发展目标是建立在 C++11 的基础上,通过提供改进和新特性来进一步完善现代 C++。它旨在为 C++ 开发者提供更多的工具和功能,以便更轻松地编写高性能、安全且易于维护的代码。

C++14 的发展背景还包括了计算机科学领域的整体进步。随着计算机硬件的发展和软件需求的增长,编程语言需要不断适应新的需求和挑战。C++14 正是在这样的背景下,通过引入新的语言特性和标准库组件,来满足这些需求,提高编程语言的一致性和可用性。

具体来说,C++14 引入了一些重要的新特性,如泛型 Lambda 表达式、返回类型推导、变量模板、聚合初始化等。这些特性使得 C++ 代码更加简洁、易读和高效。同时,C++14 还修复了 C++11 中的一些遗留问题,提高了编程语言的稳定性和可靠性。

2 变量模板

变量模板(Variable Templates)是一个强大的新特性,它支持为变量定义模板,就像为函数或类定义模板一样。这增强了模板的灵活性,并且还能够在不同的类型上复用相同的变量定义。

变量模板的基本语法是声明一个模板参数列表,后跟一个变量名。然后,可以为特定的类型实例化这个模板,创建具有该类型的变量。

下面是一个简单的示例,展示了如何使用变量模板来创建一个可以存储任何类型最大值的变量:

#include <iostream>  
#include <limits>  // 声明一个变量模板  
template <typename T>
constexpr T maxValue = std::numeric_limits<T>::max();int main() {// 使用int类型实例化变量模板  std::cout << "Max int value: " << maxValue<int> << std::endl;// 使用unsigned long long类型实例化变量模板  std::cout << "Max unsigned long long value: " << maxValue<unsigned long long> << std::endl;// 使用float类型实例化变量模板  std::cout << "Max float positive value: " << maxValue<float> << std::endl;return 0;
}

上面代码的输出为:

Max int value: 2147483647
Max unsigned long long value: 18446744073709551615
Max float positive value: 3.40282e+38

上面的代码定义了一个名为 maxValue 的变量模板,它使用了 std::numeric_limits 模板来获取给定类型的最大值。然后,在 main 函数中,分别使用 int、unsigned long long 和 float 类型来实例化这个模板,并打印出这些类型的最大值。

注意,由于 maxValue 是 constexpr 的,它必须在编译时就能够确定其值。因此,使用了 std::numeric_limits<T>::max() 来获取类型的最大值,这个函数也是在编译时确定的。

3 constexpr 常量表达式

在 C++14 中,constexpr常量表达式得到了进一步的扩展和增强,为程序员提供了更大的灵活性和更多的可能性。比如:在 C++11 中,constexpr 函数只能包含一条 return 语句,且不能包含循环、条件语句等。而 C++14 放宽了这些限制,允许 constexpr 函数包含更多的控制流语句(如 if、switch 和循环),甚至可以包含复杂的表达式和函数调用。这使得更多的函数能够在编译时计算,提高了代码的性能和可预测性。

下面是一个简单的示例,展示了 constexpr 常量表达式包含控制流语句:

#include <iostream>  
#include <array>  // constexpr 函数可以包含控制流语句  
constexpr int fibonacci(int n) {return (n <= 1) ? n : fibonacci(n - 1) + fibonacci(n - 2);
}int main() {// 使用 constexpr 函数在编译时计算 Fibonacci 数列的值  constexpr int fifthFibonacci = fibonacci(5);std::cout << "The fifth Fibonacci number is: " << fifthFibonacci << std::endl;return 0;
}

上面代码的输出为:

The fifth Fibonacci number is: 5

在这个示例中,fibonacci 函数是一个 constexpr 函数,它使用了递归,这在 C++11 中是不允许的。这展示了 C++14 中 constexpr 的灵活性和强大功能。

4 auto 类型推断

在 C++14 中,auto 类型推断得到了进一步的增强和扩展,为程序员提供了更大的便利性和灵活性。比如在 C++14 中,auto 可以用于更多类型的声明,包括复杂的表达式和函数返回值。这使得程序员能够更方便地声明变量,而无需显式指定其类型。另外 Lambda 表达式的参数也可以直接使用 auto 关键字进行类型推断。这使得 Lambda 表达式更加灵活,可以接受任意类型的参数,而无需事先声明参数的具体类型。

下面是一个简单的示例,展示了 auto 类型推断的扩展特性:

#include <iostream>  
#include <vector>  int main() {// 使用auto进行类型推断  auto num = 12;                 // int类型  auto lambda = [](auto x) { return x * 2; }; // 泛型Lambda表达式  auto vec = std::vector<int>{ 1, 2, 3, 4, 5 }; // 根据初始化列表推断类型  std::cout << lambda(num) << std::endl; // 输出84  for (auto i : vec) {std::cout << i << ' '; // 输出1 2 3 4 5  }std::cout << std::endl;return 0;
}

上面代码的输出为:

24
1 2 3 4 5

这个示例使用了 auto 来推断变量 num、Lambda 表达式 lambda 和 vector 容器 vec 的类型。Lambda 表达式使用了 auto 参数类型,使其能够接受任意类型的输入。这展示了 C++14 中 auto 类型推断的灵活性和便利性。

5 二进制字面量

C++14 引入了二进制字面量(binary literals),它允许程序员在代码中直接使用二进制数。这对于表示和操作二进制数据(比如位掩码或低级硬件操作)非常有用。

在 C++14 中,二进制字面量以 0b 或 0B 开头,后面跟着一系列 0 和 1。下面是一个简单的例子:

#include <iostream>  int main() {  int binary_number = 0b1010; // 二进制字面量  int decimal_number = 10;    // 十进制字面量  std::cout << "Binary number: " << binary_number << std::endl;  std::cout << "Decimal number: " << decimal_number << std::endl;  return 0;  
}

上面代码的输出为:

Binary number: 10
Decimal number: 10

二进制字面量允许开发者以一种更直观的方式来表示二进制数,避免了在十进制和二进制之间手动转换时可能出现的错误。这在处理低级硬件编程、位操作或者网络协议时特别有用,因为这些领域经常需要直接处理二进制数据。

注意:尽管二进制字面量在 C++14 中被引入,但它们并不是所有编译器都支持的特性。在使用二进制字面量时,请确保编译器支持 C++14 或更高版本的标准。

6 泛型 Lambda 表达式

C++14 中的泛型 Lambda 表达式(也称为通用 Lambda 或多态 Lambda)是对 C++11 Lambda 表达式的一个扩展。在 C++11 中,Lambda 表达式的捕获子句和参数类型都是固定的,而在 C++14 中,Lambda 表达式的参数类型可以省略,编译器会自动推导其类型,这使得 Lambda 表达式更加灵活和通用。

泛型 Lambda 表达式允许你在定义 Lambda 时不指定参数类型,编译器会根据 Lambda 表达式的上下文自动推断出参数类型。这使得 Lambda 表达式能够像模板函数一样接受不同类型的参数。

下面是一个简单的示例,展示了 C++14 中泛型 Lambda 表达式的使用:

#include <iostream>  
#include <vector>  
#include <algorithm>  int main() {  // 创建一个整数向量  std::vector<int> int_vector = {1, 2, 3, 4, 5};  // 创建一个浮点数向量  std::vector<double> double_vector = {1.0, 2.0, 3.0, 4.0, 5.0};  // 定义一个泛型 Lambda 表达式,用于打印容器中的元素  auto print_element = [](const auto& elem) {  std::cout << elem << ' ';  };  // 使用泛型 Lambda 表达式打印整数向量中的元素  std::for_each(int_vector.begin(), int_vector.end(), print_element);  std::cout << std::endl;  // 使用泛型 Lambda 表达式打印浮点数向量中的元素  std::for_each(double_vector.begin(), double_vector.end(), print_element);  std::cout << std::endl;  return 0;  
}

上面代码的输出为:

1 2 3 4 5
1 2 3 4 5

在上面的代码中,print_element 是一个泛型 Lambda 表达式,它的参数 elem 的类型被省略了,编译器会根据上下文自动推断其类型。因此,这个 Lambda 表达式既可以用于处理 int 类型的元素,也可以用于处理 double 类型的元素。

std::for_each 算法被用于遍历向量中的每个元素,并将每个元素传递给 print_element Lambda 表达式进行打印。由于 print_element 是一个泛型 Lambda 表达式,它可以与不同类型的容器一起使用,而无需修改 Lambda 表达式的定义。

7 std::make_unique

C++14 标准中引入的 std::make_unique 是一个用于创建 std::unique_ptr 智能指针的便捷工具。在 C++11 中,创建 std::unique_ptr 通常需要直接调用其构造函数,并显式传递 new 运算符创建的对象的原始指针。这种方式比较繁琐,并且容易出错,尤其是在处理异常安全时。

std::make_unique 简化了这个过程,它接受与要创建的对象相同的构造函数参数,并返回一个指向新创建对象的 std::unique_ptr。使用 std::make_unique 的好处在于它内部已经处理了 new 运算符的调用,并且如果构造函数抛出异常,它会确保不会泄漏内存。

下面是一个使用 std::make_unique 的简单示例:

#include <iostream>  
#include <memory> // 引入 unique_ptr 和 make_unique  // 定义一个简单的类  
class MyClass {  
public:  MyClass(int value) : value_(value) {}  void printValue() const { std::cout << "Value: " << value_ << std::endl; }  private:  int value_;  
};  int main() {  // 使用 std::make_unique 创建一个 MyClass 对象的 unique_ptr  auto ptr = std::make_unique<MyClass>(12);  // 使用 unique_ptr 调用 MyClass 的成员函数  ptr->printValue();  // 当 ptr 离开作用域时,它会自动删除所指向的 MyClass 对象  // 不需要显式调用 delete  return 0;  
}

上面代码的输出为:

Value: 12

这个示例定义了一个简单的类 MyClass,它有一个接受 int 参数的构造函数和一个打印其值的成员函数。在 main 函数中,使用 std::make_unique<MyClass>(42) 创建了一个指向 MyClass 对象的 std::unique_ptr。然后,通过 ptr 调用 printValue 方法来打印出对象的值。最后,当 ptr 离开其作用域时,它将自动删除它所指向的 MyClass 对象,因此不需要显式地调用 delete。

std::make_unique 确保了内存管理和异常安全性,因为它会在对象完全构造之后才会返回 std::unique_ptr,如果构造函数抛出异常,则不会返回任何 std::unique_ptr,从而避免了潜在的内存泄漏问题。

8 整数序列

C++14 引入了整数序列(Integer Sequences)的概念,它允许程序员在模板元编程中更方便地操作整数序列。这主要通过 std::index_sequence、std::make_index_sequence 和 std::forward_as_tuple 等模板工具来实现。这些工具在元组操作、可变参数模板展开等场景中特别有用。

std::index_sequence 是一个模板类,它表示一个整数序列,其中包含了从 0 到 N-1 的整数。std::make_index_sequence 是一个模板函数,它接受一个大小参数并生成一个相应的 std::index_sequence。

下面是一个使用 std::index_sequence 和 std::make_index_sequence 的简单示例,演示了如何对元组进行解包操作:

#include <iostream>  
#include <tuple>  
#include <utility> // for std::index_sequence, std::make_index_sequence  // 定义一个辅助模板函数,用于打印元组的元素  
template<typename Tuple, std::size_t... Is>  
void print_tuple_impl(const Tuple& t, std::index_sequence<Is...>) {  using swallow = int[];  (void)swallow{(std::cout << std::get<Is>(t) << ' ', 0)...};  std::cout << std::endl;  
}  // 定义一个包装函数,用于自动推导整数序列并调用辅助函数  
template<typename Tuple>  
void print_tuple(const Tuple& t) {  print_tuple_impl(t, std::make_index_sequence<std::tuple_size<Tuple>::value>{});  
}  int main() {  std::tuple<int, double, char> my_tuple = {1, 3.14, 'a'};  print_tuple(my_tuple); // 输出:1 3.14 a  return 0;  
}

上面代码的输出为:

1 3.14 a

这个示例定义了一个 print_tuple 函数,它接受一个元组并打印出元组中的所有元素。这个函数内部调用了一个辅助模板函数 print_tuple_impl,该函数接受一个元组和一个整数序列作为参数。std::make_index_sequence 用于根据元组的大小生成一个整数序列,然后该序列被展开以逐个访问元组中的元素。

注意,这个示例使用了 C++11 的 std::get 和 std::tuple_size,但 std::index_sequence 和 std::make_index_sequence 是 C++14 中引入的。

整数序列在模板元编程中提供了更强大的能力,能够更简洁、更安全地处理可变数量的模板参数,特别是在涉及到类型擦除和完美转发等高级技术时。

8 std::thread 线程库

C++14 对 std::thread 线程库的改进主要体现在一些细节和易用性的提升上,虽然它并没有引入大量的新功能或进行根本性的改变,但是这些改进确实让线程编程变得更加便捷和灵活。

首先,C++14 增强了 std::thread 的错误处理能力。在 C++11 中,如果尝试启动一个已经处于活动状态的线程,或者试图在线程对象析构时加入到一个还未结束的线程,都会导致程序抛出 std::system_error 异常。而在 C++14 中,这些错误情况的处理得到了进一步的明确和规范,使得开发者更容易理解和处理这些线程相关的错误。

其次,C++14 对 std::thread 的构造函数进行了一些改进,使其更加灵活。例如,现在可以使用 std::piecewise_construct 和 std::forward_as_tuple 来构造线程对象,这使得在创建线程时能够更灵活地处理构造函数的参数。

此外,C++14 还对 std::thread 的成员函数进行了一些优化。例如,joinable() 成员函数现在更加高效,能够更快地判断线程是否可以被加入(join)。这对于编写需要频繁检查线程状态的代码来说是非常有用的。

最后,虽然 C++14 没有直接对 std::thread 的功能进行大的扩展,但它通过改进其他与线程相关的库(如 std::mutex 和 std::condition_variable 等)来间接地提升了 std::thread 的使用体验。这些改进使得线程间的同步和通信变得更加容易和可靠。

总的来说,C++14 对 std::thread 线程库的改进虽然不算大,但却使得线程编程变得更加稳健和高效。这些改进有助于提高代码的质量和可维护性,同时也降低了开发者在使用线程库时可能会遇到的错误和问题的风险。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/788090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

系统学习Docker:1_Docker简介以及2_安装Docker

01-Docker简介 什么是Docker 在不同的机器和操作系统中安装运行环境和依赖库是一件很烦人的事情&#xff0c;容器就是为了解决这一问题而出现的技术。 容器是一种虚拟化技术&#xff0c;将应用程序及其依赖项&#xff08;环境、系统工具等&#xff09;打包到一个独立的可移植…

数据结构:链表的双指针技巧

文章目录 一、链表相交问题二、单链表判环问题三、回文链表四、重排链表结点 初学双指针的同学&#xff0c;请先弄懂删除链表的倒数第 N 个结点。 并且在学习这一节时&#xff0c;不要将思维固化&#xff0c;认为只能这样做&#xff0c;这里的做法只是技巧。 一、链表相交问题 …

[Linux]基础IO(中)---理解重定向与系统调用dup2的使用、缓冲区的意义

重定向理解 在Linux下&#xff0c;当打开一个文件时&#xff0c;进程会遍历文件描述符表&#xff0c;找到当前没有被使用的 最小的一个下标&#xff0c;作为新的文件描述符。 代码验证&#xff1a; ①&#xff1a;先关闭下标为0的文件&#xff0c;在打开一个文件&#xff0c;…

图神经网络GNN

图神经网络GNN B、C、D的特征在某种程度上可以代表A的特征 上面就是一次GCN的操作

整型之韵,数之舞:大小端与浮点数的内存之旅

✨✨欢迎&#x1f44d;&#x1f44d;点赞☕️☕️收藏✍✍评论 个人主页&#xff1a;秋邱’博客 所属栏目&#xff1a;人工智能 &#xff08;感谢您的光临&#xff0c;您的光临蓬荜生辉&#xff09; 1.0 整形提升 我们先来看看代码。 int main() {char a 3;char b 127;char …

vue3父子组件之间的传值方式

在vue3中&#xff0c;可以使用props和emit来实现父子组件之间的通信。子组件可以使用emit发出一个事件&#xff0c;父组件监听这个事件&#xff0c;并将数据传递给另一个子组件。 下面的简单例子中&#xff0c;ChildA组件有一个按钮&#xff0c;当按钮被点击时&#xff0c;会触…

WebKit结构简介

WebKit是一款开源的浏览器引擎&#xff0c;用于渲染网页内容。它负责将HTML、CSS和JavaScript等网络资源转换为用户在屏幕上看到的图形界面。WebKit是一个跨平台的引擎&#xff0c;可以在多种操作系统上运行&#xff0c;如Windows、macOS、Linux等。 以下是一篇关于WebKit结构…

信创咨询岗位需求分析

岗位职责 1.深入了解国内IT解决方案市场&#xff0c;熟悉不同领域的国产产品&#xff0c;包括但不限于云计算、大数据、人工智能等。 2.跟踪国内科技发展趋势&#xff0c;了解最新的国产技术和产品&#xff0c;以为客户提供最适合的解决方案。 3.能够撰写清晰、详细的技术文档&…

浅谈iOS开发中的自动引用计数ARC

1.ARC是什么 我们知道&#xff0c;在C语言中&#xff0c;创建对象时必须手动分配和释放适量的内存。然而&#xff0c;在 Swift 中&#xff0c;当不再需要类实例时&#xff0c;ARC 会自动释放这些实例的内存。 Swift 使用 ARC 来跟踪和管理应用程序的内存&#xff0c;其主要是由…

[从0开始AIGC][Transformer相关]:Transformer中的激活函数:Relu、GELU、GLU、Swish

[从0开始AIGC][Transformer相关]&#xff1a;Transformer中的激活函数 文章目录 [从0开始AIGC][Transformer相关]&#xff1a;Transformer中的激活函数1. FFN 块 计算公式&#xff1f;2. GeLU 计算公式&#xff1f;3. Swish 计算公式&#xff1f;4. 使用 GLU 线性门控单元的 FF…

关于矩阵的摄动。

在研究信号处理算法的过程中&#xff0c;凡是涉及到矩阵求逆的算法&#xff08;只要包括解线性方程组&#xff09;&#xff0c;都要考虑矩阵的摄动&#xff0c;即受到轻微扰动&#xff0c;矩阵的逆会不会有巨大到不能接受的变化。 为了刻画这种扰动&#xff0c;定义相对于某范…

[Rust开发]用可视化案例讲Rust编程6.动态分发与最终封装

全系列合集 [Rust开发]用可视化案例讲Rust编程1.用Rust画个百度地图 [Rust开发]用可视化案例讲Rust编程2. 编码的核心组成&#xff1a;函数 [Rust开发]用可视化案例讲Rust编程3.函数分解与参数传递 [Rust开发]用可视化案例讲Rust编程4.用泛型和特性实现自适配shapefile的读取 […

YOLOv8全网独家改进: 小目标 |新颖的多尺度前馈网络(MSFN) | 2024年4月最新成果

💡💡💡本文独家改进:多尺度前馈网络(MSFN),通过提取不同尺度的特征来增强特征提取能力,2024年最新的改进思路 💡💡💡创新点:多尺度前馈网络创新十足,抢先使用 💡💡💡如何跟YOLOv8结合:1)放在backbone后增强对全局和局部特征的提取能力;2)放在detect…

C语言一维数组及二维数组详解

引言&#xff1a; 小伙伴们&#xff0c;我发现我正文更新的有些慢&#xff0c;但相信我&#xff0c;每一篇文章真的都很用心在写的&#xff0c;哈哈&#xff0c;在本篇博客当中我们将详细讲解一下C语言中的数组知识&#xff0c;方便大家后续的使用&#xff0c;有不会的也可以当…

每日一题:C语言经典例题之水仙花

题目描述 春天是鲜花的季节&#xff0c;水仙花就是其中最迷人的代表&#xff0c;数学上有个水仙花数&#xff0c;它是这样定义的&#xff1a;“水仙花数”是指一个三位数&#xff0c;它的各位数字的立方和等于其本身&#xff0c;比如&#xff1a;153135333。请输出所有的“水仙…

公司只有一个测试,要怎么继续呆下去?

在面试的时候&#xff0c;面试官可能会问&#xff1a;小公司、小团队&#xff0c;岗位就你一个人&#xff0c;怎么做 &#xff1f; 或者已经有的小伙伴已经在公司中面临只有一个测试的处境&#xff0c;这个时候我们应该怎么处理呢&#xff1f; 一 原因分析 公司只有一个测试人…

OSPF中配置静态路由实验简述

静态路由协议和OSPF&#xff08;开放最短路径优先&#xff09;协议是两种常见的路由协议&#xff0c;它们在路由选择和网络管理方面有一些区别。他们可以共存。 静态路由协议需要手动配置路由表&#xff0c;不会自动适应网络拓扑变化&#xff0c;适用于小型网络或者网络拓扑变化…

MySQL Innodb 引擎中预防 Update 操作上升为表锁

一、MySQL 如何预防 Update 上升为表锁 在 MySQL 中&#xff0c;进行任何数据的 修改 操作都会进行一定的锁操作&#xff0c;而锁的不同直接导致性能的差异。例如 MyISAM 引擎&#xff0c;更新时采用表锁&#xff0c;并发性较差。而 Innodb 引擎支持事务&#xff0c;更新时采用…

Windows SDK(五)按钮静态文本与编辑框控件

我们首先应该知道&#xff0c;所谓按钮静态文本等等控件都是窗口&#xff0c;他们都是隶属于父窗口下的子窗口&#xff0c;所 以在创建控件前&#xff0c;我们要首先创建一个父窗口&#xff0c;此处我们直接使用Windows桌面程序创建时&#xff0c;程 序自动为我们创建的一个窗…

类和对象(下)--- 初始化列表、explicit、友元、static、匿名对象和内部类

本篇将会对类和对象的主要知识收尾&#xff0c;先会对构造函数进行补充&#xff0c;分别补充了构造函数体赋值、初始化列表、explicit 关键字&#xff0c;然后介绍 static 成员知识以及友元、内部类还有匿名对象等知识点&#xff0c;目录如下&#xff1a; 目录 1. 构造函数补充…