auto
keyword appeared in C ++ 11, the life of programmers has become easier. Thanks to this keyword, the compiler can output the types of variables at compile time, which saves us from having to always specify the types ourselves. This turned out to be very convenient, for example, in cases when you have to work with data types like map<string,vector<pair<int,int>>>
. When using the auto
keyword you need to take into account some features. Consider an example: auto an_int = 26; // , - int auto a_bool = false; // bool auto a_float = 26.04; // float auto ptr = &a_float; // auto data; // #1 ? - .
#1
(hereinafter, in a similar way, we will mark the lines that we will, after the examples, parse). There is no initializer in this line, you cannot do this. The code located in this line does not allow the compiler to know what the type of the corresponding variable should be.auto
keyword in C ++ were pretty limited. Then, in more recent versions of the language, auto
features were added. Here is another example: auto merge(auto a, auto b) // auto! { std::vector<int> c = do_something(a, b); return c; } std::vector<int> a = { ... }; // #1 - std::vector<int> b = { ... }; // #2 - auto c = merge(a,b); //
#1
and #2
, the variable is initialized using curly brackets - another new feature of C ++ 11.auto
keyword, the compiler must have some way to infer the type of the variable.auto a = {1, 2, 3}
? What is it? Vector, or the reason for the compilation error?std::initializer_list<type>
. The list of initialization values in parentheses will be treated as a container when using the auto
keyword. void populate(auto &data) { // ! data.insert({"a",{1,4}}); data.insert({"b",{3,1}}); data.insert({"c",{2,3}}); } auto merge(auto data, auto upcoming_data) { // auto result = data; for(auto it: upcoming_data) { result.insert(it); } return result; } int main() { std::map<std::string, std::pair<int,int>> data; populate(data); std::map<std::string, std::pair<int,int>> upcoming_data; upcoming_data.insert({"d",{5,3}}); auto final_data = merge(data,upcoming_data); for(auto itr: final_data) { auto [v1, v2] = itr.second; // #1 std::cout << itr.first << " " << v1 << " " << v2 << std:endl; } return 0; }
#1
. The expression auto [v1,v2] = itr.second
is a new C ++ 17 feature. This is the so-called decomposition when declaring variables. In previous versions of the language, it was necessary to extract each value separately. Thanks to this mechanism, it has become much more convenient to perform such operations.auto &[v1,v2] = itr.second
. std::vector<std::pair<int,int>> data = {{1,3}, {7,6}, {12, 4}}; // std::sort(begin(data), end(data), [](auto a, auto b) { // - auto! return a.second < b.second; });
begin()
and end()
constructs, which also appeared in C ++ 11. Then comes the lambda function used as a mechanism for comparing data. The parameters of this function are declared using the auto
keyword, this feature appeared in C ++ 14. Previously, this keyword could not be used to describe the parameters of functions.[]
. This is the so-called mask of variables. It defines the scope of the expression, that is, it allows you to manage the relationship of the lambda expression with local variables and objects.[]
- the expression does not capture anything. This means that in lambda expressions one cannot use local variables from the external field of view to it. Only parameters can be used in an expression.[=]
- the expression captures the values of local objects (that is, local variables, parameters). This means that they can be used, but not modified.[&]
- expression captures references to local objects. They can be modified, it is shown in the following example.[this]
- the expression captures the value of the this
pointer.[a, &b]
- the expression captures the value of the object a
and a reference to the object b
. std::vector<int> data = {2, 4, 4, 1, 1, 3, 9}; int factor = 7; for_each(begin(data), end(data), [&factor](int &val) { // factor val = val * factor; factor--; // #1 - , - factor }); for(int val: data) { std::cout << val << ' '; // 14 24 20 4 3 6 9 }
factor
variable would be accessed by value (then, when describing the lambda expression, the mask of the [factor]
variables would be used), then in line #1
the factor
value could not be changed - simply because we would not have rights to performing such an operation. In this example, we have the right to such actions. In such situations, it is important not to abuse the possibilities that access to variables has by reference.val
also carried out by reference. This allows you to ensure that data changes occurring in the lambda function affect the vector
. std::set<int> input = {1, 5, 3, 6}; if(auto it = input.find(7); it==input.end()){ // - , - std::cout << 7 << " not found" << std:endl; } else { // else it std::cout << 7 << " is there!" << std::endl; }
if
or switch
block. This contributes to the writing of neat code. Here is a schematic description of the considered construction: if( init-statement(x); condition(x)) { // } else { // x // }
constexpr
gives us great opportunities. Suppose we have a certain expression that needs to be calculated, while its value, after it initializes the corresponding variable, will not change. Such an expression can be calculated in advance and used as a macro. Or, what has become possible in C ++ 11, use the constexpr
. #include <iostream> constexpr long long fact(long long n) { // constexpr return n == 1 ? 1 : (fact(n-1) * n); } int main() { const long long bigval = fact(20); std::cout<<bigval<<std::endl; }
constexpr
.constexpr
, the compiler can calculate the fact(20)
value in advance during the compilation of the program. As a result, after compilation, the string const long long bigval = fact(20);
can be replaced by const long long bigval = 2432902008176640000;
.constexpr
. The arguments passed to them must also be declared using the constexpr
or using the const
keyword. Otherwise, such functions will behave like normal functions, that is, during compilation, their values will not be calculated in advance.constexpr
. In such a case, as it is easy to guess, the values of these variables must be calculated at compile time. If this cannot be done, a compilation error message will be displayed.pair
data structure, the tuple
data structure (tuple) is a collection of values of different types of fixed size. Here is an example: auto user_info = std::make_tuple("M", "Chowdhury", 25); // auto // std::get<0>(user_info); std::get<1>(user_info); std::get<2>(user_info); // C++ 11 tie std::string first_name, last_name, age; std::tie(first_name, last_name, age) = user_info; // C++ 17, , auto [first_name, last_name, age] = user_info;
tuple
data structure, it is more convenient to use std::array
. This data structure is similar to simple arrays used in the C language, with additional features from the standard C ++ library. This data structure appeared in C ++ 11. std::pair<std::string, int> user = {"M", 25};
std::pair user = {"M", 25};
std::tuple<std::string, std::string, int> user ("M", "Chy", 25);
std::tuple user2("M", "Chy", 25);
Source: https://habr.com/ru/post/451870/
All Articles