"Effective modern C + +" translation-clause 2: Understanding auto Automatic type Deduction

Source: Internet
Author: User

Article 2: Understanding Auto Automatic type Deduction

If you've read article 1 about template type deduction, you almost already know all about auto type deduction. As for why auto type deduction is the template type deduction there is only one place to be curious. What is that? That is, template type deduction includes templates, functions, and parameters, and auto type inference does not have to deal with them.

It's true, of course, but it's okay. Template type deduction and auto auto type deduction are directly matched. Literally, it is the conversion from one algorithm to another.

In clause 1, the description of template type deduction is based on a regular function template:

template<typename T>void f(ParamType param);

And is a regular method to invoke:

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

In the process of calling F, the compiler infers the type of T and paramtype through expr.

When declaring a variable with the Auto keyword, the Auto keyword plays the role of T in the above template, and the type specifier has the same role as the Paramtype player. More clearly than the language description is to show them, so take a look at this example:

auto x = 27;

This way, the type specifier for X is the same as yourself. On the other hand, this statement:

constauto cx = x;

The type descriptor here is Const Auto. And here:

constauto& rx = x;

The type specifier is const auto& at this time. To infer the X,CX and RX variables in the above examples, the compiler serves to provide a template for each declaration and invoke the templates using the appropriate initialization expressions:

Template<typename t>//conceptual Template forDeducing x' s typevoid func_for_x (T param); Func_for_x ( -); Conceptual Call:param' sdeducedtype  isX' s typeTemplate<typename t>//conceptual Template forDeducing CX' s typevoid func_for_cx (const T param);             FUNC_FOR_CX (x); Conceptual Call:param' sdeducedtype  isCx' s typeTemplate<typename t>//conceptual Template forDeducing Rx' s typevoid Func_for_rx (const t& param);             FUNC_FOR_RX (x); Conceptual Call:param' sdeducedtype  isRx' s type

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

In clause 1, the template type deduction is divided into three cases according to Paramtype and the type descriptor param in the regular template. In the case of variable type deduction through auto, the type specifier replaces the Paramtype, but is also divided into three cases:

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

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

? The third case: the type descriptor is neither a pointer nor a reference.

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

auto27;           //case 3 (x is neither ptr nor reference)constauto cx = x;     //case 3 (cx isn‘t either)constauto& rx = x;    //case 1 (rx is non-universal ref.)

The second situation is as you would expect:

auto&& uref1 = x;       isand lvalue, so uref1‘stypeis int&auto&& uref2 = cx;      isand lvalue, so uref2‘stypeis27;      //27isand rvalue, so uref3‘stypeis int&&

Clause 1 summarizes how arrays and function names degenerate into pointers for non-reference type specifiers. This, of course, also applies to the auto type deduction:

const char name[] ="R. N. Briggs"; Name' s type  isConst char[ -]auto arr1 = name; Arr1' s type  isConst char*auto& ARR2 = name; Arr2' s type  isconst char (&) [ -]void somefunc (int, double); SomeFunc isAfunction;type  isvoid (int, double) auto func1 = SomeFunc; Func1' s type  isvoid (*) (int, double) auto& func2 = SomeFunc; Func2' s type  isvoid (&) (int, double)

As you can see, the auto type deduction is really the same as the template type deduction. Just like the two sides of a coin.

You must expect the difference. Let me start by observing declaring a variable and initializing it to 27, in c++98, you have two syntax choices:

int27;int x2(27);

This is also added in the c++11:

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

All in all, four grammars have one result, which is to initialize the variable to 27.

However, as explained in clause 5, using auto instead of a fixed type to declare a variable has many advantages, so use the Auto keyword instead of the int type in the program above. The simple text substitution we get is this code:

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

All of these can be compiled, but the meaning of the representation is different than the previous. The first two of the above four expressions actually declare a variable with a value of type 27int. And then two, is declaring a type and std::initializer_list<int> having an element with a value of 27!

27;        //type27auto x2(27);         //同上auto x3 = {27};      //typestd::initializer_list<int>, value is {27}auto x4{27};         //同上

This is because the auto type derives rules that have special customs. When the type declared for auto is initialized with enclosing curly braces, the inferred type is std::initializer_list. If such a type cannot be inferred, such an encoding is rejected by the compiler:

auto x5 = {123.0//error! can‘t deduce T for std::initializer_list<T>

As suggested in the previous note, type inference fails in this case, but it is more important to recognize that two types of derivation are used at this time. One is to complete the type deduction of X5 through Auto. Since X5 is initialized with curly braces, X5 must be inferred as a std::initializer_list type. But Std::initializer_list is a template. For std::initializer_list<int>
The instantiation of the T is required to deduce the type of the. Such type deduction takes place in the jurisdiction of the second type deduction: template type derivation. In this example, the type derivation fails because the initialization value does not have a single type.

There is a difference between auto type deduction and template type deduction for initializing with curly braces. When an auto variable is initialized with curly braces, the inferred type is the type of std::initializer_list instantiation. If a template faces a type deduction for curly brace initialization, such code is rejected. (clause 32 will explain the perfect forwarding)

You'll wonder why there are special rules for the auto type deduction when you initialize the curly braces, but the template type deduction does not. I myself have doubts about that. Unfortunately, I can't find a convincing explanation. But the rule is the rule, which means that you have to be mindful of the std::initializer_list of the argument that the auto derivation of curly braces initializes. It is particularly important to keep this in mind if you face the idea of enclosing the initialized values in curly braces as a matter of course. In c++11 programming, one of the most typical errors is that you want to declare a variable of another type , but declare an std:: initializer_list variable. To reiterate:

27;    //xand x2 are intsauto x2(27);auto x3 = {27};  //xandstd::initializer_list<int>sauto x4{27};

This trap allows some developers to use curly braces to initialize variables only when they are forced to do so. (We'll discuss it in clause 7.) )

For c++11, this is all about, but for c++14, the story continues. C++14 allows auto to deduce the return value of the function (see clause 3), and the lambda expression in c++14 can use auto type deduction when the parameter is declared. However, the auto deduction used here is based on the rules of the template derivation, not the auto type derivation rules. This means that the use of curly braces to initialize will cause type deduction to fail. So a function that uses auto as the return type returns a variable that is initialized with curly braces does not pass:

auto createInitList(){    return {123type for {1, 2, 3}}

The same applies to the lambda expression in c++14, which uses auto as a parameter (thus producing a generic lambda expression):

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 end result is that if you do not initialize with curly braces, the auto type deduction is consistent with the template type deduction. In this case only (with curly braces for initialization), Auto is deduced as an std:: initializer_list, but the template type deduction fails.

Please remember:

The auto type object is usually the same as the template type deduction.

The only exception is that when initialized with auto and curly braces, it is automatically deduced as std::initializer_lists.

? For initialization with parentheses, the template type deduction fails.

"Effective modern C + +" translation-clause 2: Understanding auto Automatic type Deduction

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.