
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