c ++函数功能查询器
目录 (Table of Contents)
介绍 (Introduction)
In this article, we will talk about the new features of the new C++17 standard.
在本文中,我们将讨论新的C ++ 17标准的新功能。
The article presents real examples that will help a beginner in the new standard of the language to understand faster how to apply new features in practice.
本文提供了真实的示例,这些示例将帮助使用该语言新标准的初学者更快地了解如何在实践中应用新功能。
The code in the sections was tested in Visual Studio 2017.
本节中的代码已在Visual Studio 2017中进行了测试。
(You can click on the image to view the enlarged, original image here.)
(您可以单击图像在此处查看放大的原始图像。)
设置集成开发环境(IDE) (Settings an Integrated Development Environment (IDE))
Regardless of the IDE, you will most likely have to configure it to work with the latest C ++ standard.
无论使用哪种IDE,您都极有可能必须对其进行配置以使其与最新的C ++标准兼容。
I work with Visual Studio 2017, so I’ll show you how to set it up to work with the new standard:
我使用Visual Studio 2017,因此我将向您展示如何设置它以与新标准一起使用:
设置C ++版本 (Set C++ Version)
To set on compiler option for the Visual Studio project, follow these steps:
要为Visual Studio项目设置编译器选项,请按照下列步骤操作:
- In the Solution Explorer window, right-click the project name, and then choose Properties to open the project Property Pages dialog (or press ALT + ENTER). 在“解决方案资源管理器”窗口中,右键单击项目名称,然后选择“属性”以打开项目的“属性页”对话框(或按ALT + ENTER键)。
- Select the Configuration properties > C/C++ > Language property page. 选择配置属性> C / C ++>语言属性页面。
In the property list, select the drop-down for the "Conformance mode" property, and then choose /permissive.
在属性列表中,选择“ 一致性模式 ”属性的下拉列表,然后选择/ permissive 。
It will disable non-standard C++ extensions and will enable standard conformance in VS2017.
它将禁用非标准C ++扩展,并在VS2017中启用标准一致性。
In the property list, select the drop-down for the "C++ Language Standard" property, and then choose /std:c++17 or /std:c++latest.
在属性列表中,选择“ C ++语言标准 ”属性的下拉列表,然后选择/ std:c ++ 17或/ std:c ++ latest 。
Press the "OK" button to save your changes.
按“ 确定 ”按钮保存更改。
To enable the latest features of the new standard, you can also take a different approach:
要启用新标准的最新功能,您还可以采用其他方法:
- Open the project's Property Pages dialog box. 打开项目的“属性页”对话框。
Select "Configuration Properties"-> "C/C++"->"Command Line".
选择“ 配置属性 ”->“ C / C ++ ”->“ 命令行 ”。
Add to "Additional Options" textbox following param: /std:c++17 or /std:c++latest
在参数后添加到“ 其他选项 ”文本框: / std:c ++ 17或/ std:c ++ latest
Press the "OK" button to save your changes.
按“ 确定 ”按钮保存更改。
结构绑定 (Structure Binding)
Multiple return values from functions are not a new concept in programming and similar functionality is present in many other programming languages. C++17 comes with a new feature (structured bindings) that provides functionality similar to the multiple return values provided in other languages.
函数的多个返回值并不是编程中的新概念,并且许多其他编程语言中也存在类似的功能。 C ++ 17带有一项新功能(结构化绑定),其功能类似于其他语言提供的多个返回值。
In the following example, I want to provide an overview of some of the options that we have in the old C++ standard, in the modern standard (C++11/14) and today in C++17 to return multiple values from functions:
在下面的示例中,我想概述一下旧的C ++标准,现代的标准(C ++ 11/14)和今天的C ++ 17中从函数返回多个值的一些选项。 :
1 #include <iostream>
2 #include <tuple> // std::tie
3
4 const double PI = 3.14159265;
5
6 void calculateSinCos(const double param, double & resSin, double & resCos)
7 {
8 resSin = sin(param * PI / 180.0); // converting degrees to radians
9 resCos = cos(param * PI / 180.0); // converting degrees to radians
10 }
11
12 std::pair<double, double> calculateSinCos(const double param)
13 {
14 return { sin(param * PI / 180.0), cos(param * PI / 180.0) };
15 }
16
17 std::tuple<double, double> calculateSinCos_Tuple(const double param)
18 {
19 return std::make_tuple(sin(param * PI / 180.0),
20 cos(param * PI / 180.0)); // packing values into tuple
21 }
22
23 int main()
24 {
25 double param { 90.0 };
26 double resultSin { 0.0 };
27 double resultCos { 0.0 };
28
29 //C++98
30 calculateSinCos(param, resultSin, resultCos);
31 std::cout << "C++98 : sin(" << param << ") = " <<
32 resultSin << ", cos(" << param << ") = "
33 << resultCos << "\n";
34
35 //C++11
36 const auto resSinCos(calculateSinCos(param));
37 std::cout << "C++11 : sin(" << param << ") = " <<
38 resSinCos.first << ", cos(" << param << ") = "
39 << resSinCos.second << "\n";
40
41 //C++11
42 std::tie(resultSin, resultCos) = calculateSinCos(param);
43 std::cout << "C++11 : sin(" << param << ") = " <<
44 resultSin << ", cos(" << param << ") = "
45 << resultCos << "\n";
46
47 // C++17
48 auto[a, b] = calculateSinCos(param);
49 std::cout << "C++17 :
50 sin(" << param << ") = " << a << ",
51 cos(" << param << ") = " << b << "\n";
52
53 // C++17
54 auto[x, y] =
55 calculateSinCos_Tuple(param); // std::make_tuple(sin(val), cos(val));
56 std::cout << "C++17 :
57 sin(" << param << ") = " << x << ",
58 cos(" << param << ") = " << y << "\n";
59 }
Let's look at the above code:
让我们看一下上面的代码:
In this approach:
在这种方法中:
calculateSinCos(param, resultSin, resultCos);
we used the oldest and possibly still most common method - using the OUTPUT params passed as reference can be used to "return" values to the caller.
我们使用了最古老且可能仍是最常见的方法-使用作为参考传递的OUTPUT参数可以将值“返回”给调用者。
Consider the different way to access multiple values returned from functions:
考虑访问从函数返回的多个值的不同方法:
const auto resSinCos(calculateSinCos(param));
Accessing the individual values of the resulting
std::pair
byresSinCos.first
andresSinCos.second
was not very expressive, since we can easily confuse the names, and it’s hard to read.通过
resSinCos.first
和resSinCos.second
访问生成的std::pair
的各个值并不是很容易表达,因为我们很容易混淆名称,而且很难阅读。Alternatively, before C++17, it would be possible to use
std::tie
to unpack a tuple/pair to achieve a similar effect:或者,在C ++ 17之前,可以使用
std::tie
解开一个元组/对,以达到类似的效果:std::tie(resultSin, resultCos) = calculateSinCos(param);
This approach demonstrates how to unpack the resulting pair into two variables. Notice, this example shows all the power of
std::tie
, but nonetheless, thestd::tie
is less powerful than structured bindings, because we must first define all the variables we want to bind.该方法演示了如何将结果对分解为两个变量。 注意,此示例显示了
std::tie
所有功能,但是std::tie
的功能不如结构化绑定,因为我们必须首先定义要绑定的所有变量。Structured binding is a new functionality of C++17, making the code even more readable, expressive and concise.
结构化绑定是C ++ 17的一项新功能 ,使代码更具可读性,表达力和简洁性。
auto[a, b] = calculateSinCos(param);
Notice, the variables
a
andb
are not references; they are aliases (or bindings) to the generated object member variables. The compiler assigns a unique name to the temporary object.注意,变量
a
和b
不是引用; 它们是生成的对象成员变量的别名(或绑定)。 编译器为临时对象分配一个唯一的名称。In C++11, the
std::tuple
container has been added to build a tuple that contains multiple return values. But neither C++11 nor C++14 does support an easy way to get elements in astd::tuple
directly from the tuple (Of course, we can unpack a tuple usingstd::tie
, but we still need to understand the type of each object and how many objects are this tuple. Phew, how painful it is...)在C ++ 11中,已添加
std::tuple
容器以构建包含多个返回值的元组。 但是C ++ 11和C ++ 14都不支持直接从元组中获取std::tuple
元素的简单方法(当然,我们可以使用std::tie
解开元组的std::tie
,但是我们仍然需要了解每个对象的类型以及该元组有多少个对象。Ph,这是多么痛苦...)C++17 fixes this flaw, and the structured bindings allow us to write code as follows:
C ++ 17修复了此缺陷,结构化绑定使我们可以编写如下代码 :
auto[x, y] = calculateSinCos_Tuple(param);
Let's see the output of the above code of structure binding:
让我们看一下上面的结构绑定代码的输出:
As we can see, different approaches show the same result....
我们可以看到,不同的方法显示出相同的结果。
带有初始化程序的“ if”和“ switch”语句 ('if' and 'switch' Statements with Initializers)
Good programming style limits the scope of variables. Sometimes, it is required to get some value, and only if it meets a certain condition can it be processed further.
好的编程风格会限制变量的范围。 有时,需要获得一定的价值,并且只有在满足特定条件的情况下,才能对其进行进一步处理。
For this purpose, C++17 provides a new version of the 'if
' statement with initializer.
为此,C ++ 17提供了带有初始化程序的' if
'语句的新版本。
if (init; condition)
Let's see how the 'if
' condition worked before the new C++17 standard:
让我们看看' if
'条件在新的C ++ 17标准之前如何工作:
#include <iostream>
int getValueOfNumber() {
return 5;
}
int main() {
int num = getValueOfNumber();
if (num > 100) {
std::cout << "The value of the num is greater than 100" << std::endl;
}
else {
std::cout << "The value of the num is less than or equal to 100" << std::endl;
}
std::cout << "num =" << num << std::endl;
}
Please notice that the num
value is visible inside the if
and else
statements, as well as OUTSIDE the scope conditions.
请注意, num
值在if
和else
语句以及范围条件之外均可见。
Now, in C++17, we can write:
现在,在C ++ 17中,我们可以编写:
#include <iostream>
int getValueOfNumber() {
return 5;
}
int main() {
if (auto num = getValueOfNumber(); num > 100) {
std::cout << "The value of the num is greater than 100" << std::endl;
}
else {
std::cout << "The value of the num is less than or equal to 100" << std::endl;
}
std::cout << "num =" << num;
}
If we try to compile the above code, we will get the following error:
如果我们尝试编译以上代码,则会收到以下错误:
Now, num
is visible only INSIDE the if
and else
statements, so accessing a variable outside the scope of if
/else
causes an error...
现在, num
仅在if
和else
语句内部可见,因此访问if
/ else
范围之外的变量会导致错误...
The same applies to switch
statements.
这同样适用于switch
语句。
C++17 provides new version of the 'switch
' statement with initializers.
C ++ 17提供了带有初始化程序的新版本的' switch
'语句。
switch (init; condition)
Let's see how the 'switch
' condition worked before the new C++17 standard:
让我们看看在新的C ++ 17标准之前' switch
'条件是如何工作的:
#include <iostream>
#include <cstdlib>
#include <ctime>
int getRandomValueBetween_1_and_2() {
srand(time(NULL));
return rand() % 2 + 1; // // value in the range 1 to 2
}
int main() {
int num = getRandomValueBetween_1_and_2();
switch (num) {
case 1:
std::cout << "num = 1 \n"; break;
case 2:
std::cout << "num = 2 \n"; break;
default:
std::cout << "Error value in num ! \n";
}
std::cout << "Value output outside the 'switch': num =" << num << std::endl;
}
Please notice that the num
value is visible inside the switch
statements, as well as OUTSIDE the scope conditions.
请注意, num
值在switch
语句内部以及范围条件之外均可见。
Now, in C++17, we can write:
现在,在C ++ 17中,我们可以编写:
#include <iostream>
#include <cstdlib>
#include <ctime>
int getRandomValueBetween_1_and_2() {
srand(time(NULL));
return rand() % 2 + 1; // value in the range 1 to 2
}
int main() {
switch (auto num(getRandomValueBetween_1_and_2()); num) {
case 1:
std::cout << "num = 1 \n"; break;
case 2:
std::cout << "num = 2 \n"; break;
default:
std::cout << "Error value in num ! \n";
}
std::cout << "Value output outside the 'switch': num =" << num << std::endl;
}
If we try to compile the above code, we will get the following error:
如果我们尝试编译以上代码,则会收到以下错误:
Now, num is visible only INSIDE the switch
statements, so accessing a variable outside the scope of switch
causes an error...
现在,num仅在switch
语句内部可见,因此访问switch
范围之外的变量会导致错误...
Due to the described mechanism, the scope of the variable remains short. Before C++17, this could only be achieved with additional {curly braces}.
由于所描述的机制,该变量的范围仍然很短。 在C ++ 17之前,只能通过附加的{curly braces}来实现。
The short lifetimes reduce the number of variables in scope, keeping code clean and making refactoring easier.
较短的生命周期减少了作用域中的变量数量,从而保持了代码的整洁并使重构更加容易。
Thus, this new C++17 feature is very useful for further use.
因此,此新的C ++ 17功能对于进一步使用非常有用。
Constexpr Lambdas和捕获* this by Value (Constexpr Lambdas and Capturing *this by Value)
As it is written here: "In C++11 and later, a lambda expression—often called a lambda—is a convenient way of defining an anonymous function object (a closure) right at the location where it is invoked or passed as an argument to a function. Typically, lambdas are used to encapsulate a few lines of code that are passed to algorithms or asynchronous methods. This article defines what lambdas are, compares them to other programming techniques, describes their advantages, and provides a basic example."
就像这里写的那样:“在C ++ 11和更高版本中,lambda表达式(通常称为lambda)是一种在调用或传递匿名函数对象(即闭包)的位置处定义匿名函数对象(闭包)的便捷方法。通常,lambda用于封装传递给算法或异步方法的几行代码本文定义了lambda,将其与其他编程技术进行比较,描述它们的优势,并提供一个基本示例。 ”
C++17 offers two significant improvements to lambda expressions:
C ++ 17对lambda表达式进行了两项重大改进:
constexpr lambdas
constexpr lambdas
capture of *this
捕获* this
constexpr lambdas (constexpr lambdas)
Lambda expressions are a short form for writing anonymous functors introduced in C++11, which have become an integral part of modern C++ standard. Using the constexpr keyword, also introduced in C++11, we can evaluate the value of a function or variable at compile time. In C++17, these two entities are allowed to interact together, so lambda can be invoked in the context of a constant expression.
Lambda表达式是编写C ++ 11中引入的匿名函子的一种简短形式,匿名函子已成为现代C ++标准不可或缺的一部分。 使用也在C ++ 11中引入的constexpr关键字,我们可以在编译时评估函数或变量的值。 在C ++ 17中,允许这两个实体一起交互,因此可以在常量表达式的上下文中调用lambda。
For example:
例如:
constexpr auto my_val {foo()};
Declaring the variable my_val
with the constexpr
modifier will ensure that the function object it stores will be created and initialized at compile time.
使用constexpr
修饰符声明变量my_val
将确保在编译时创建并初始化存储的函数对象。
In the definition of a lambda expression, we can use the optional constexpr
parameter:
在lambda表达式的定义中,我们可以使用可选的constexpr
参数:
[capture clause] (parameter list) mutable costexpr exception-specification -> return-type
{
}
If we explicitly mark the lambda expression with the constexpr keyword, then the compiler will generate an error when this expression does not meet the criteria of the constexpr function. The advantage of using constexpr
functions and lambda expressions is that the compiler can evaluate their result at compile time if they are called with parameters that are constant throughout the process. This will result in less code in the binary later. If we do not explicitly indicate that lambda expressions are constexpr
, but these expressions meet all the required criteria, then they will be considered constexpr
anyway, only implicitly.
如果我们用constexpr关键字显式标记lambda表达式,则当该表达式不符合constexpr函数的条件时,编译器将生成错误。 使用constexpr
函数和lambda表达式的优点是,如果在整个过程中使用不变的参数调用它们,则编译器可以在编译时评估其结果。 稍后将减少二进制代码的数量。 如果我们没有明确指出lambda表达式是constexpr
,但是这些表达式满足所有必需的条件,则无论如何,它们都将被视为constexpr
,只是隐式地。
For example:
例如:
constexpr auto NvalueLambda = [](int n) { return n; }; // implicitly constexpr
If we want the lambda expression to be constexpr
, then it is better to explicitly set it as such, because in case of errors the compiler will help us identify them by printing error messages.
如果我们希望lambda表达式为constexpr
,则最好将其设置为这样,因为在发生错误的情况下,编译器将通过打印错误消息来帮助我们识别它们。
Let's look at an example demonstrating how C++17 evaluates statically (at compile time) lambda expressions and functions:
让我们看一个示例,该示例演示C ++ 17如何静态(在编译时)评估lambda表达式和函数:
#include <iostream>
constexpr int Increment(int value) {
return [value]