C++ 有着每 3 年以标准形式引入新的改进和功能的传统。随着最后一个标准于 2017 年发布为 C++ 17,C++20 将成为最新标准。以下是 C++ 20 的一些主要功能:
- C++ Concepts library
- 3-way comparisons
- Map contains
- Range-based for loop
- New identifiers ( import, module)
- Calendar and time zone library
- std::string functions
- Array bounded/unbounded
- std::to_array
- Likely and unlikely attributes
C++ Concepts library:
概念库提供了基本库概念的定义,可用于执行模板参数的编译时验证并根据类型的属性执行函数分派。这些概念为程序中的教育推理提供了基础。 本节大约有 15 个概念,这些概念应该是不言自明的。这些概念表达了类型、类型分类和基本类型属性之间的关系。
Defined in header <concepts> Defined in namespace std
- integral: Specifies that a type is an integral type.
- signed_integral: Specifies that a type is an integral type that is signed.
- unsigned_integral: Specifies that a type is an integral type that is unsigned.
- floating_point: Specifies that a type is a floating-point type.
- same_as: Specifies that a type is the same as another type.
- derived_from: Specifies that a type is derived from another type.
- convertible_to: Specifies that a type is implicitly convertible to another type.
- common_with: Specifies that two types share a common type.
template<class T>
concept integral = is_integral_v<T>;
template<class T>
concept signed_integral = integral<T> && is_signed_v<T>;
template<class T>
concept unsigned_integral = integral<T> && !signed_integral<T>;
template<class T>
concept floating_point = is_floating_point_v<T>;
3-way comparisons:
lhs <=> rhs
<=>,它的官方 C++ 名称是三向比较运算符。之所以如此称呼,是因为它通过比较两个对象,然后将结果与 0 进行比较来使用:
(x <=> y) < 0 is true if x < y
(x <=> y) > 0 is true if x > y
(x <=> y) == 0 is true if x and y are equal/equivalent.
三向比较运算符不仅可以表达对象之间的顺序和相等性,还可以表达关系的特征。宇宙飞船运算符是 C++ 中非常受欢迎的补充。它为我们提供了如何定义关系的更多表现力,允许我们编写更少的代码来定义它们,并避免手动实现某些比较运算符的一些性能缺陷。
// C++ program to illustrate the
// above concepts
#include <bits/stdc++.h>
#include <compare>
using namespace std;
// Driver Code
int main()
{
int a = 91, b = 110;
auto ans1 = a <=> b;
if (ans1 < 0) {
cout << "a < b\n";
}
else if (ans1 == 0) {
cout << "a == b\n";
}
else if (ans1 > 0) {
cout << "a > b\n";
}
vector<int> v1{ 3, 6, 9 };
vector<int> v2{ 3, 6, 9 };
auto ans2 = v1 <=> v2;
if (ans2 < 0) {
cout << "v1 < v2\n";
}
else if (ans2 == 0) {
cout << "v1 == v2\n";
}
else if (ans2 > 0) {
cout << "v1 > v2\n";
}
cout << endl;
}
Map/Set contains:
std::map<Key, T, Compare, Allocator>::contains
std::set<T>::contains
它提供了一种更简单的方法来检查 C++20 中的关联容器(集合或映射)中是否存在键。它取代了 find 内置函数。
// C++ program to illustrate the
// above concepts
#include <iostream>
#include <map>
// Driver Code
int main()
{
// Map
std::map<int, char> M = { { 1, 'a' },
{ 2, 'b' } };
// Check if M has key 2
if (M.contains(2)) {
std::cout << "Found\n";
}
else {
std::cout << "Not found\n";
}
return 0;
}
Range-based for loop with Initialization:
基于范围的 for 循环在 C++17 中进行了更改,以允许 begin() 和 end() 表达式具有不同类型,并且在 C++20 中引入了 init 语句来初始化循环范围中的变量。它允许我们初始化我们希望在范围声明本身中循环的容器。
for (init-statement(optional) range_declaration : range_expression)
{
/* loop body */
}
// C++ program to illustrate the
// above concepts
#include <iostream>
using namespace std;
// Driver Code
int main()
{
for (std::vector v{ 1, 2, 3 }; auto& e : v) {
std::cout << e;
}
}
New identifiers(import, module):
- 模块有助于将大量代码划分为逻辑部分。模块承诺更快的编译时间、宏的隔离,并使头文件变得冗余。
- 它们表达了代码的逻辑结构,并有助于摆脱丑陋的宏解决方法。模块与命名空间正交。导入模块的顺序没有区别。
- 模块使您能够表达代码的逻辑结构。您可以显式指定应导出或不导出的名称。此外,您可以将几个模块捆绑到一个更大的模块中,并将它们作为逻辑包提供。
- 使用模块,现在无需将源代码分为接口和实现部分。
// C++ program to illustrate the
// above concepts
// helloworld.cpp module declaration
export module helloworld;
// Import declaration
import<iostream>;
// Export declaration
export void hello()
{
std::cout << "Hello world!\n";
}
// main.cpp import declaration
import helloworld;
// Driver Code
int main()
{
hello();
}
Calendar and time zone library:
C++ 11/14 的计时库扩展了日历和时区功能。日历由多种类型组成,分别表示年、月、工作日中的某一天或一个月中的第 n 个工作日。这些基本类型可以与复杂类型组合,例如year_month、year_month_day、year_month_day_last、years_month_weekday 和year_month_weekday_last。重载运算符“/”是为了方便指定时间点。此外,我们将获得 C++20 新的文字:d 代表一天,y 代表一年。
由于扩展了 chrono 库,以下功能很容易实现:
- Get the last day of a month.
- Get the number of days between two dates.
- Printing the current time in various time-zones.
Defined in header <chrono>
Defined in namespace std::chrono
auto date1 = 2020y/sep/8;
auto date2 = 21d/oct/2018;
auto date3 = jan/27/2019;
std::string functions:
ends_with(“suffix”): Checks if the string ends with the given suffix.
starts_with(“prefix”) :Checks if the string view starts with the given prefix.
// C++ program to illustrate the
// above concepts
#include <iostream>
using namespace std;
// Driver Code
int main()
{
std::string str = "GeeksforGeeks";
// Check string str starts_with Geeks
if (str.starts_with("Geeks")) {
std::cout << "true" << endl;
}
else {
std::cout << "false" << endl;
}
// Check string str ends_with Geeks
if (str.ends_with("for")) {
std::cout << "true" << endl;
}
else {
std::cout << "false" << endl;
}
}
Array bounded/unbounded:
- 它检查 T 是否是未知边界的数组类型,如果 T 是未知边界的数组类型,则提供等于 true 的成员常量值。否则,值等于 false。
- 它检查 T 是否是已知边界的数组类型,如果 T 是已知边界的数组类型,则提供等于 true 的成员常量值。否则,值等于 false。
// C++ program to illustrate the
// above concepts
#include <iostream>
#include <type_traits>
// Class A
class A {
};
// Driver Code
int main()
{
std::cout << std::is_unbounded_array_v<A> << '\n';
std::cout << std::is_unbounded_array_v<A[3]> << '\n';
std::cout << std::is_unbounded_array_v<int[]> << '\n';
std::cout << std::is_unbounded_array_v<int> << '\n';
std::cout << std::is_bounded_array_v<A> << '\n';
std::cout << std::is_bounded_array_v<A[3]> << '\n';
std::cout << std::is_bounded_array_v<float> << '\n';
std::cout << std::is_bounded_array_v<int> << '\n';
}
std::to_array:
它将给定的数组/“类数组”对象转换为 std::array。它从一维内置数组 a 创建一个 std::array 。 std::array 的元素是从 a 的相应元素复制初始化的。不支持复制或移动多维内置数组。
// C++ program to illustrate the
// above concepts
#include <iostream>
using namespace std;
// Driver Code
int main()
{
// Returns std::array<char, 5>
std::to_array("Geeks");
std::to_array<int>(
{ 1, 2, 3 });
int a[] = { 1, 2, 3 };
// Returns std::array<int, 3>`
std::to_array(a);
}
likely and unlikely attributes:
它向优化器提供了一个提示:标记语句可能/不可能执行其主体。这两个属性都允许向优化器提供提示,无论执行路径的可能性更大还是更小。
// C++ program to illustrate the
// above concepts
#include <iostream>
using namespace std;
// Driver Code
int main()
{
int n = 40;
[[likely]] if (n < 100) { cout << n * 2; }
[[unlikely]] while (n > 100)
{
n = n / 2;
cout << n << endl;
}
n = 500;
[[likely]] if (n < 100) { cout << n * 2; }
[[unlikely]] while (n > 100)
{
n = n / 2;
cout << n << endl;
}
return 0;
}