Effective modern C + + translator (3)-clause 2

Source: Internet
Author: User

Article 2 Understanding Auto type derivation

If you've read through clause 1 about the derivation of template types, you know almost everything about the auto type deduction, because except for an odd exception, the type deduction rules for auto and the type deduction rules for templates are the same, but why? The type deduction of a template involves templates, functions, and arguments, but the type derivation of auto does not involve any of them.

This is true, but it does not matter, there is a direct mapping between the auto type derivation and the template, and one can be converted verbatim to another.

In clause 1, the template type deduction is illustrated in the following template form:

Template<typename t>void f (paramtype param);

Function calls are like this

// call function f with some expressions

In the function call of F, the compiler uses expr to deduce the type of T and Paramtype.

When a variable is declared with auto, Auto plays the role of T in the template, the type specifier for the variable (the type specifier) is equivalent to Paramtype, which is easier to interpret with an example, consider the following example:

Auto x=;

The type specifier for x here is auto itself, on the other hand, in the following declaration:

const Auto cx=x;

The type descriptor is Const auto.

const auto& rx=x;

The type specifier is const auto& In the above example, in order to derive the type of X,cx,rx, the compiler pretends that each declaration is a template and is invoked with the corresponding initialization expression (compilers act as if there were a template for each declaration as-a call-to-that-template with the corresponding initializing expression:)

Template<typename t>// generate a conceptual template tovoidfunc_for_x (T param);//deduce the type of xFunc_for_x ( -);//conceptual function calls, parameters                                  // The derived type is the type of xTemplate<typename t>// generate a conceptual template tovoidFUNC_FOR_CX (ConstT param);//deduce the type of CXFUNC_FOR_CX (x);// conceptual function calls, parameters                                  //The derived type is the type of CXTemplate<typename t>//generate a conceptual template tovoidFUNC_FOR_RX (Constt& param);//deduce the type of CXFUNC_FOR_RX (x);// conceptual function calls, parameters                                  //The derived type is the type of RX

As I said, the type deduction of auto is the same as the type deduction of the template.

Clause 1 The type deduction of the template is divided into 3 cases according to the type of paramtype, similarly, in the variable that auto declares, the type specifier of the variable (the type specifier) is equivalent to Paramtype, so the auto type deduction also has 3 cases:

    • Case 1: The type specifier is a pointer or a reference, but not a universal reference (Universal Reference)
    • Scenario 2: The type descriptor is a universal reference (Universal Reference)
    • Scenario 3: The type descriptor is neither a pointer nor a reference

We've already given an example of condition 1 and condition 3 above.

;        //  const Auto cx = x;  // Article 3 (CX is neither a pointer nor a reference) Const // clause 1 (RX is not a universal reference)

Situation 2, as you might think.

auto&& uref1 = x;    // the type of x is int and is an lvalue so the type of UREF1 is auto&& uref2 = cx;                          The type of CX is const int and is an                       lvalue so the type of UREF2 is const int&Auto  ;    The type of 27 is int and is an rvalue                      //  so the type of UREF3 is  int&&

Clause 1 also discusses that arrays and function names are degraded to pointer types under the type specifier of non-reference types, which of course applies to the type deduction of auto

Const CharName[] ="R. N. Briggs";//name is of type const CHAR[13] name ' s type is const CHAR[13]Auto arr1= name;//the type of arr1 is const char*auto& arr2 = name;//the type of ARR2 is                                    //const char (&) [+]voidSomeFunc (int,Double);//SomeFunc is a function;                                    //type is void (int, double)Auto func1 = SomeFunc;//the type of func1 is                                    //Void (*) (int, double)auto& Func2 = SomeFunc;//the type of FUNC2 is                                    //Void (&) (int, double)

As you can see, the auto type deduction is actually the same as the template type deduction, they are equivalent to the positive and negative two sides of the coin.

But at a point they are different if you want to put a declaration of a variable whose initial value is 27,c++98, you can use the following two syntaxes

int  - ; int X2 (+);

In c++11, support for unified set initialization (uniform initialization) is provided, and the following is the declaration method.

int x3 = {+}; int x4{};

All in all, the result of the above 4 declarations is the same, declaring a variable whose initial value is 27.

However, as explained in clause 5, using AUTO to declare a variable is more advantageous than using a deterministic type declaration, so it would be nice to replace the int in the above code variable declaration with auto, and the substitution of the direct text resulted in the following code:

 - Auto X2 (= {};auto x4{};

These declarations can be compiled, but they are not all the same as the substitution before, the first two did declare a variable of type int, the initial value is 27; However, the latter two declare a variable of type std::initializer_list<int>, It consists of an element with an initial value of 27;

;    // The type is int and the initial value isauto x2();     // ditto Auto x3 = {+};  // type is std::initializer_list<int>                  // the initial value isauto x4{.     // Ibid .

This is due to a special rule derived from auto type, when the variable is initialized with curly brace initialization (braced initializer), the type being pushed is std::initializer_list, if the type cannot be inferred (for example, The elements in the initializer of the curly braces have different types), and the code will not pass.

Auto x5 = {123.0//  Error! Unable to derive the type of T in Std::initializer_list<t>


As noted in the note, type derivation fails in this case, but it is important to recognize that there are two forms of type derivation, one from the use of auto, the X5 type needs to be deduced, and because auto is initialized with curly braces initialized, The X5 type must be deduced as std::initializer_list, but Std::initializer_list is a template, so instantiating the template std::initizalizer_list<t> means that the type of T must be deduced, and in the example above, the type derivation of the template fails because the variable type in the curly braces is not consistent.

The difference between the initializer for curly braces (braced initializer) is the only difference between auto type deduction and template type deduction, when the auto variable is initialized with a curly brace initializer (braced initializer). The derived type is the type of the std::initializer_list template that is instantiated, and the template type infers the initialization of the brace (braced initializer) when the code does not pass (this is due to the perfect forwarding perfect Forwarding results, will be explained in clause 32)

You might wonder why the auto type derivation has a special rule for curly braces (braced initializer), and template type derivation is not, I'd like to know, unfortunately, I didn't find an appealing explanation, but the rules are rules, which means that You have to remember that if you declare a variable with auto, and initialize it with curly brace initialization, the derived type is always std::initializer_list, and you have to keep this in mind if you want to use the unified set initialization more deeply. Especially important to bear the "if you embrace the philosophy of uniform initialization of enclosing Initializin G values in braces as a matter of course.) One of C++11 's most classic mistakes is that programmers accidentally declare a variable of type std::initializer_list, but they want to declare a variable of a different type. Let me reiterate:

;    // x1 and x2 are int type Auto X2 (= {);  // X3 and x4 are auto x4{};     // std::initializer_list<int> Type

The main reason for the trap is that some programmers only use curly braces for initialization when necessary (this pitfall is one of the reasons some developers put braces around their initial Izers only when they has to. (When you have to be discussed in clause 7)

For c++11, this is a complete story, but for C++14, the story is not over, C++14 allows auto to indicate that a function's return type needs to be deduced (see clause 3), and that the lambda expression of c++14 may need to use auto when declaring a parameter. In any case, these auto uses are based on the rules of the template type derivation, not the auto type deduction rules, which means that the initialization of the curly braces will cause the type deduction to fail, so a function with the auto return type will not compile if the initializer that returns a curly brace is returned.

Auto Createinitlist () {return123 };   Error: Cannot infer the                    type of}//  {1, 2, 3}

Similarly, the rules apply to the parameter type specifier of the lambda that is used by auto for c++14, which produces a generic lambda (generic lambda).

=[&v] (const//123 });                        // the error cannot be deduced. Type of                                               //{1, 2, 3}

The end result is that the auto type deduction and the template type deduction are identical unless (1) A variable is declared, (2) its initialization is initialized with curly braces (its initializer is inside braces), only in this case, Auto is deduced as std::initializer_list, and the template will fail.

Please remember:

    • The type deduction for auto is usually identical to the template type deduction.
    • The only exception is when the variable is declared with auto and initialized with curly braces, auto is deduced as std::initializer_list.
    • The template type deduction fails when the initialization of the brace (braced initializer) is initialized.

Effective modern C + + translator (3)-clause 2

Related Article

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.