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

Source: Internet
Author: User

Article 3 Understanding Decltype

Decltype is an interesting thing, give it a variable name or an expression, Decltype will tell you the name of the variable or the type of the expression, usually tell you the result is the same as you predicted, but the occasional result will make you scratching your heads, start looking for some reference materials to study, Or find the answers online.

We start with a typical example, because its results are what we expected, and template type deduction compared to auto type deduction (see clause 1 and Clause 2), Decltype almost always returns the variable name or the type of the expression without any modification

Const inti =0;//Decltype (i) is a const intBOOLFConstwidget& W);//Decltype (w) is a const widget&                           //Decltype (f) is bool (const widget&)structPoint {intx, y;//Decltype (POINT::X) is an int};//Decltype (point::y) is an intWidget W;//Decltype (W) is a Widgetif(f (w)) ...//Decltype (f (w)) is boolTemplate<typename t>//simple version of Std::vectorclassVector { Public:...  T&operator[] (std::size_t index); ...}; Vector<int> v;//Decltype (v) is vector<int>... ..if(v[0] ==0) ...//Decltype (V[i]) is int&

Look, there's nothing surprising about that.

In c++11, the primary use of Decltype is when the return type of a function template depends on the type of the parameter. For example, we want to write a function whose parameters have a container that supports subscript operations and an index value, the function authenticates the user first, and then returns the result of the subscript operation, so the return type of the function should be the same as the result type of the subscript operation.

The [] operator typically returns T&,STD when it is on a container that is an element of T::d Eque is like this, std::vector is almost the same, the only exception is for std::vecotr<bool>,[] The operator does not return a bool& instead, it returns a completely new object, clause 6 will explain why, but it is important to remember that the return type of the [] operator acting on the container depends on the container itself.

Decltype makes this simple, here is the first version we wrote, showing the method of using Decltype to derive the return type, which can be streamlined, but let's not consider this for the moment:

Auto Authandaccess (container& C, Index i)//-Decltype (C[i])                                  return c[i  ];}   

There is no relationship between auto and type deduction before the function name, which implies that the semantics of the c++11 return type (trailing return) are being used, for example: The return type of the function will be declared after the argument list (after, after), tracing the return type

The advantage is that the parameters of the function can be used in the declaration of the return type, for example, in authandaccess, we use C and I to specify the return type of the function, if we want to declare the return type in front of the function name, like a traditional function, C and I cannot be used, Because they haven't been declared yet.

With this declaration, authandaccess returns the type of the [] operator when it is acting on the container, as we want.

C++11 allows derivation of the return type of a lambda for a single statement, c++14 extends this so that the return type of lambda and all functions (including functions with multiple statements) can be deduced, which means that in c++14 we can omit the trace return type (trailing return type), leaving only auto, in this form of declaration, auto means that type deduction will occur, in detail, it means that the compiler will derive the function's return type from the implementation of the function:

Auto Authandaccess (container& C, Index i)//{//                                                    return c[i];                                 // }

But what kind of C + + type inference rules will be used? Is the type deduction rule for the template or auto, or Decltype?

Maybe the answer will be a bit surprising, the function with auto return type infers rules using template type, although it seems that the type deduction rules of Auto are more consistent with this semantics, but the template type deduction rules and auto type deduction rules are almost identical, The only difference is that the template type deduction rules fail when confronted with the initializer (braced initializer) of the curly braces.

In this case, it is problematic to infer the return type of authandaccess using the template type deduction rules, but the auto type derivation rules are not much better, and the difficulty stems from their handling of lvalue expressions.

As we discussed before, most [] operators return a t& on a container with the element T, but clause 1 explains that during template type deduction, the reference portion of the initialization expression is ignored and the following customer code is considered. Authandaccess is used with the auto return type, which derives its return type using the template type deduction:

std::d eque<int>5/                            / //                          // not by compiling!

Here, D[5] returns a Int&, but for the authandaccess function, the derivation of the auto return type removes the reference part, so the resulting return type is int, and as the return type of the function, int is a right value, The code above attempts to assign 10 to an rvalue of type int, which is forbidden in C + +, so the above code cannot be compiled.

The problem is that we are using a template type deduction rule, which discards the reference qualifier in the initialization expression. So in this case, what we want is the Decltype type rule, and the Decltype type deduction allows us to make sure that the type authandaccess return and the expression C[i] type are exactly the same.

C + + rule-makers (the Guardians of C + +), it is expected that in some cases type derivation requires the use of Decltype type deduction rules, so the decltype (auto) specifier appears in c++14, which may seem a bit contradictory at first ( Decltype and Auto?), but in fact they are perfectly reasonable, auto illustrates that the type needs to be deduced, Decltype illustrates that the Decltype type deduction should be used in the derivation, so authandaccess code would be the following:

decltype (Auto)//authandaccess (container& C, Index i)//                                           {                                            // improved   authenticateuser (); return c[i];}

Now the type returned by Authandaccess will be exactly the same as the type returned by C[i], and Authandaccess will return a t& when C[i] returns a t&, and when C[i] returns an object, Authandaccess also returns an object.

The use of the Decltype (auto) is not limited to the return type of the function, and you can use it to declare a variable when you want to deduce the initialization using the Decltype type deduction.

Const widget& CW =cw;           //                                                                                                  ////////const widget&

But I know that there are two things that will bother you, one is why authandaccess still need improvement, now let's fill this section.

Let's take another look at the Authandaccess function declaration under the C++14 version:

Template<typename Container, TypeName index> decltype (Auto) authandaccess (Container& C, Index i);

A container is passed in with a very constant reference to an lvalue, because returning a reference to an element in a container allows us to modify the container, but this means that we cannot pass an rvalue container to the function, and the right value is not bound to an lvalue reference (unless it is a constant lvalue reference, But not in this case)

Admittedly, passing an rvalue container to authandaccess is a boundary condition, an rvalue container, as a temporary object will be destroyed after the statement containing the Authandaccess function call ends (would typically be destroyed At the end of the statement containing the call to authandaccess), which means that a reference to an element in the container (which is usually returned by the authandaccess function) will be suspended at the end of the invocation statement ( And that means, a reference to an element in this container (which is typically what authandaccess would return) would Dangle at the end of the statement that created it). However, it makes sense to pass a temporary object into Authandaccess, where a customer may simply want to copy an element from this temporary container, for example:

std::d eque<std::string/                                                                                      /////5 );

Supporting this use means that we need to modify the C declaration so that he can accept both Lvalue and rvalue, which means that C needs to be a universal reference (Universal Reference) (see clause 26)

Template<typename Container, TypeName index> decltype (Auto) authandaccess (Container&& C, Index i);

In this template, we don't know what type of container we operate on, which means that we ignore the type of element that the container subscript corresponds to. Passing a value to an unknown object usually requires an unnecessary copy, an object being split (see clause 17), and ridicule from colleagues, but according to examples in the standard library (e.g. Std::string,std::vector and std::d eque), It seems reasonable in this case, so we insist on passing by value.

Now all you have to do is update the template implementation, with the warning in clause 27, using Std::forward to complete

decltype (Auto)//authandaccess (container&& C, Index i)//                                         return std::forward<container> (c) [i];}   

This version can do anything we want to do, but need a compiler that supports C++14, if you don't, you need to use a c++11 version, which is similar to the c++14 version, except that you need to label the returned type yourself.

  Auto                                         //authandaccess (container&& C, Index i)        //  version -Decltype (std::forward< container>return std::forward<container>(c) [ I]; }

Another question that deserves your nagging. I've already labeled the beginning of this article, and Decltype's results are almost as good as you'd expect, and it's no surprise that you're hardly likely to encounter the exception to this rule unless you're a very large repository of implementations.

In order to fully understand Decltype's behavior, you need to familiarize yourself with some special situations, most of which prove to be very obscure in this book, but one of them will make us more aware of the use of Decltype.

Using Decltype for a variable name produces the type that declares the variable, but, as I said, there is an lvalue expression, but this does not affect the behavior of decltype, because for an lvalue expression that is more complex than the variable name, Decltype ensures that the inferred type is always a reference to an lvalue. This means if an lvalue expression differs from the type of the variable name T (that is, if the lvalue expression other than a name has type T), the Decltype deduced type will be t& , because the type inside most lvalue expressions typically contains a qualifier for an lvalue reference, for example, a function that returns an lvalue always returns a reference.

Here is a notable place to

int x=0;

X is the name of a variable, so the result of Decltype (x) is int, but the name X is wrapped up in parentheses, "(x)" produces an expression more complex than the name, as a variable name, X is an lvalue, C + + also defines (x) is also an lvalue, so Decltype ( (x)) The result is int& wrapping a variable in parentheses changes the original result of the Decltype.

In c++11, this can only be a bit odd, but with the support of Decltype (auto) in c++14, some simple changes to the return statement will affect the result of the function's final derivation.

int 0  return x;   //   int 0 return//} 

Note that F2 and F1 are not just different on return types, F2 returns a reference to a local variable, and the result of this code is undefined, and you certainly don't want this to happen.

What you need to remember is that when you use Decltype (auto), it is important to note that some seemingly insignificant details affect the results deduced by Decltype (Auto), and in order to ensure that the type of the pushed export is what you expect, you can use the technology described in Clause 4.

But at the same time do not lose the attention to the overall situation, decltype (whether used independently or with auto) the results of the deduction may be occasionally surprising, but this does not occur frequently, usually, the results of decltype and the type you expect, This is especially true when Decltype is applied to variable names, because in this case, what Decltype does is provide the declaration type of the variable.

Please remember

    • Decltype almost always returns the variable name or the type of the expression without any modification.
    • For an lvalue expression different from the variable name, the result of Decltype is always t&.
    • C++14 provides support for Decltype (auto), such as auto, which infers the type from its initialization, but uses the derivation rules of the decltype.

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

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.