Effective Modern C ++ translation-Clause 2: Understanding auto automatic type Derivation

Source: Internet
Author: User

Effective Modern C ++ translation-Clause 2: Understanding auto automatic type Derivation

Clause 2: Understand auto type deduction

If you have read section 1 about template type derivation, you have almost all about auto type derivation. As to why auto type derivation is a template type derivation, there is only one curiosity. What is that? That is, template type derivation includes templates, functions, and parameters, while auto type inference does not have to deal with them.

This is true, but it does not matter. Template type derivation directly matches auto automatic type derivation. Literally, it is just converting from one algorithm to another.

In Clause 1, the conventional function template is used to deduce the template type:

template
  
   void f(ParamType param);
  

And it is a conventional method for calling:

f(expr);    //call f with some expression

During the f call process, the compiler uses expr to export the T and ParamType types.

When the auto keyword is used to declare a variable, the auto keyword plays the T role in the preceding template, and the type specifier plays the same role as ParamType. It is clearer than the language description to show them, so please refer to the example below:

auto x = 27;

In this way, the type specifiers of x are the same as those of their own. On the other hand, the statement is as follows:

const auto cx = x;

The type description here is const auto. Here:

const auto& rx = x;

The type description is const auto &. To infer the x, cx, and rx variables in the above examples, the compiler provides a template for each declaration and uses the corresponding initialization expression to call these templates:

template
  
           //conceptual template for deducing x's typevoid func_for_x(T param);   func_for_x(27);             //conceptual call: param's deduced type is x's typetemplate
   
            //conceptual template for deducing cx's typevoid func_for_cx(const T param);   func_for_cx(x);             //conceptual call: param's deduced type is cx's typetemplate
    
             //conceptual template for deducing rx's typevoid func_for_rx(const T& param);   func_for_rx(x);             //conceptual call: param's deduced type is rx's type
    
   
  

As I mentioned earlier, auto type derivation is the same as template type deduction.

In Clause 1, template type derivation is divided into three types based on ParamType And param type specifiers in the conventional template. When auto is used to deduce the variable type, the type specifier replaces ParamType, but it is also divided into three situations:

? First case: the type specifier is a pointer or reference, but not a universal reference.

? The second case: the type description is a universal reference.

? Case 3: The type specifier is neither a pointer nor a reference.

Let's take a look at the first and third cases:

auto x = 27;           //case 3 (x is neither ptr nor reference)const auto cx = x;     //case 3 (cx isn't either)const auto& rx = x;    //case 1 (rx is non-universal ref.)

The second case is as expected:

auto&& uref1 = x;       //x is int and lvalue, so uref1's type is int&auto&& uref2 = cx;      //cx is const int and lvalue, so uref2's type is const int&auto&& uref3 = 27;      //27 is int and rvalue, so uref3's type is int&&

Clause 1 summarizes how non-reference operators, arrays and function names are degraded to pointers. Of course, this applies to auto type deduction:

const char name[] = "R. N. Briggs";  //name's type is const char[13]auto arr1 = name;                    //arr1's type is const char*auto& arr2 = name;                   //arr2's type is const char (&)[13]void someFunc(int, double);       //someFunc is a function; type is void(int, double)auto func1 = someFunc;              //func1's type is void(*)(int, double)auto& func2 = someFunc;             //func2's type is void(&)(int, double)

As you can see, the auto type derivation is the same as the template type derivation. It is like two sides of a coin.

You must expect the difference between the two. Let me declare a variable and initialize it to 27. In C ++ 98, two syntax options are provided:

int x1 = 27;int x2(27);

This is also added in C ++ 11:

int x3 = {27};int x4{27};

In short, the four syntaxes get a result, that is, the variable is initialized to 27.

However, as Clause 5 explains, using auto instead of a fixed type to declare variables has many advantages, so using the auto keyword instead of the int type in the above program. After a simple text is replaced, we get the following code:

auto x1 = 27;auto x2(27);auto x3 = {27};auto x4{27};

All of the above can be compiled, but the meaning is different from the previous one. The first two of the above four expressions actually declare a variable of the 27int type. The last two are declaredstd::initializer_list And has an element with a value of 27!

Auto x1 = 27; // type is int, value is 27 auto x2 (27); // same as auto x3 = {27}; // type is std: initializer_list
  
   
, Value is {27} auto x4 {27}; // same as above
  

This is because the auto type derivation has special rules. When closed braces are used for initialization of the type declared by auto, the derived type is std: initializer_list. If such a type cannot be deduced, such encoding is rejected by the compiler:

auto x5 = {1, 2, 3.0}; //error! can't deduce T for std::initializer_list
  

As prompted in the preceding annotations, type derivation fails in this case, but more importantly, two types of derivation are used at this time. One is to use auto to deduce the x5 type. Because x5 is initialized using braces, x5 must be deduced as std: initializer_list. However, std: initializer_list is a template. Forstd::initializer_list
T type needs to be deduced. This type of derivation takes place. The second type is subject to the template type deduction. In this example, type deduction fails because the initialization value does not have a single type.

For initialization with braces, there is a difference between auto type derivation and template type derivation. When an auto variable is initialized by braces, the derived type is the type of std: initializer_list instantiation. If a template faces type derivation for braces initialization, such code is rejected. (Clause 32 will explain the perfect forwarding)

You may wonder why there are special rules for auto type derivation when initializing braces, but not for template type derivation. I am also skeptical about this. Unfortunately, I cannot find a convincing explanation. But the rule is the rule, which means that you must keep in mind the variables initialized with braces during auto deduction. The derivation type is always std: initializer_list. This is especially important to remember this point, if you faceThe initialization value enclosed in braces is taken for granted as the initialization concept. In C ++ 11 programming, the most typical error is that you want to declare another type.But declare a std: initializer_list variable. Reiterate:

auto x1 = 27;    //x1 and x2 are intsauto x2(27);auto x3 = {27};  //x3 and x4 are std::initializer_list
  
   sauto x4{27};
  

This trap allows some developers to use braces to initialize variables only when they are forced. (We will discuss it again in clause 7 .)

For C ++ 11, this is all content, but for C ++ 14, the story continues. C ++ 14 allows auto to be used to deduce the return value of a function (see clause 3), and lambda expressions in C ++ 14 can be deduced using the auto type when declaring parameters. However, the auto deduction here uses the template deduction rules, rather than the auto type deduction rules. This means that initialization using braces will cause type deduction failure. Therefore, the function that uses auto as the return type returns a variable initialized with braces. Compilation fails:

auto createInitList(){    return {1, 2, 3}; //error: can't deduce type for {1, 2, 3}}

The same principle applies to lambda expressions in C ++ 14 using auto as a parameter (so a general lambda expression is generated ):

std::vector v;....auto resetV = [&v](const auto& newValue) { v = newValue;};//C++14 only....resetV({1, 2, 3});            //error! can't deduce type for {1, 2, 3}

The final result is that if you do not use braces for initialization, the auto type derivation is consistent with the template type derivation. In this case only (initialization using braces), auto is deduced as a std: initializer_list, but the template type deduction fails.

Remember:

? The auto type object is usually the same as the template type derivation.

? The only exception is that when auto and braces are used for initialization, std: initializer_lists is automatically deduced.

? Template type deduction fails when parentheses are used for initialization.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.