New Feature of C ++ 0x in VC10: Right Value reference (rvalue references) (3)

Source: Internet
Author: User

 

The original text address is here. For more information, see the source.

New Feature of C ++ 0x in VC10: Right Value reference (rvalue references) (2)

Right reference: Template parameter derivation and reference folding

The right value reference and template interact in a special way. The following is an example:

C:/temp> type collapse. cpp
# Include <iostream>
# Include <ostream>
# Include <string>
Using namespace STD;

Template <typename T> struct name;

Template <> struct name <string> {
Static const char * Get (){
Return "string ";
}
};

Template <> struct name <const string> {
Static const char * Get (){
Return "const string ";
}
};

Template <> struct name <string &> {
Static const char * Get (){
Return "string &";
}
};

Template <> struct name <const string &> {
Static const char * Get (){
Return "const string &";
}
};

Template <> struct name <string &> {
Static const char * Get (){
Return "string &&";
}
};

Template <> struct name <const string &> {
Static const char * Get (){
Return "const string &&";
}
};

Template <typename T> void Quark (T & T ){
Cout <"T:" <t <Endl;
Cout <"T:" <name <t>: Get () <Endl;
Cout <"T &:" <name <t &>: Get () <Endl;
Cout <Endl;
}

String strange (){
Return "Strange ()";
}

Const string charm (){
Return "charm ()";
}

Int main (){
String up ("up ");
Const string down ("down ");

Quark (up );
Quark (down );
Quark (strange ());
Quark (charm ());
}

C:/temp> Cl/ehs/ nologo/W4 collapse. cpp
Collapse. cpp

C:/temp> collapse
T: Up
T: string &
T &: string &

T: Down
T: const string &
T &: const string &

T: Strange ()
T: String
T &: string &&

T: charm ()
T: const string
T &: const string &&

Here the explicit and special name helps us print the type name.

When we call Quark (up), the compiler first derives the template type parameters. Quark is a function template whose template parameter is T. However, when we call it, we do not explicitly provide type parameters (such as Quark <x> (up )), instead, the type parameters of the template are derived by comparing the type & and real parameters of the function (the left value of a string type.

C ++ 0x converts the type of the real parameter and the type of the parameter, and then matches them together.

First, the compiler converts the real parameter type of the function. OneSpecial rules(N2798 14.8.2.1 [temp. deduct. call]/3) activated: When a function parameter type is T & (T is a template parameter), the function real parameter is the left value of the type, use a & to derive template parameters. (This special rule is not applicable when the real parameter of the function is T & or const T &. It will be deduced according to the C ++ 98/03 rule. This special rule does not apply to const T &&.) In the case of quark (up), special rules are applied. The real parameter type is converted to string &.

Then, the compiler converts the function parameter type. c ++ 98/03 and C ++ 0x both ignore references (C ++ 0x ignores the left value reference and the right value reference ), during all four calls, T & is converted into T.

Therefore, we export T as the real parameter type of the function. This is why Quark (up) Outputs "T: string &", Quark (down) Outputs "T: const string &", and both up and down are left values, so they activate the special rule. Strange () and charm () are the right values, so they use normal rules. This is why Quark (strange () Outputs "T: string ", quark (charm () Outputs "T: const string.

After the template parameter is deduced, the compiler starts the replacement operation. The compiler replaces each existing T with the push type. In Quark (strange (), T is a string, so T & is a string &&. Similarly, in Quark (charm (), T is a const string, so T & is a const string &&. However, Quark (UP) and Quark (down) Activate another special rule.

In Quark (up), T is the string &, T & replacement operation, resulting in the result string &&&. References referenced in C ++ 0x will degrade, and the reference degradation rule is "reference of the Left value is contagious", X &, X &&&, and X &, both degraded to X &, and only X & degraded to X &&. Therefore, string & degrades to string &. In a template function, parameters that seem to reference the right value are not necessarily. Quark (up) is instantiated as Quark <string &> (). In this instance,Parameter T & changed to string &. We have observed this through name <t & >:: get. Similarly, Quark (down) is instantiated as Quark <const string &> (), and the T & parameter is changed to const string &. In C ++ 98/03, you may be used to hiding constants in template parameters. (A function template that accepts the T & parameter can be called using the const Foo object; change T & to const Foo &). In C ++ 0x, the left value can also be hidden in function template parameters.

Okay, so let's ask what these two special rules bring to us? In Quark (), T & has the same left and right values and constant attributes as real parameters. Therefore, you can use the right value to reference this feature to retain the left and right values and constants of real parameters for perfect forwarding.

Perfect forwarding: STD: Forward () and STD: identity how to work

Let's take a look at outer () again ():

Template <typename T1, typename T2> void outer (T1 & T1, T2 & T2 ){
Inner (Forward <t1>(T1 ),Forward <t2>(T2 ));
}

Now we understand why outer () accepts parameter types as T1 & and T2. In this way, all information about outer () arguments is retained. But why does it call forward <t1> () and forward <t2> ()? Recall that all the named left value references and named right value references are left values. If outer () calls inner (T1, T2), the parameters received by inner () will always be the left value, and the forwarding will not be perfect.

Fortunately, the anonymous left value reference is the left value, while the anonymous right value reference is the right value. Therefore, to forward t1 and t2 to inner (), we need to use helper functions to save their type information but remove their names. This is the function of STD: Forward:

Template <typename T> struct identity {
Typedef T type;
};

Template <typename T> T & forward (typename identity <t >:: type & T ){
Return T;
}

When we call forward <t1> (T1), identity does not change the type of T1 (we will see what it has done in a moment ). Therefore, forward <t1> () accepts the parameter T1 & and returns T1 &&. This ensures that the type of T1 is not changed (no matter what it is: string &, const string &, string &, const string &) and its name is removed. Inner () will receive forward <t1> (T1), which has the same left and right value/constant attribute as T1. This is the working principle of perfect forwarding.

You may ask what will happen if you write forward <t1> (T1) as forward <t1 &> (T1) (this is a common error, because the outer parameter is T1 &&). Fortunately, this will not lead to any bad results. Because forward <t1 &> () accepts and returns the T1 & type, it degrades to T1 &&. Therefore, forward <t1> (T1) and forward <t1 &> (T1) are the same, but the preceding format is shorter and therefore more popular.

What does identity do? Why can't the following forms work?

Template <typename T> T & forward (T & T){// Broken
Return T;
}

If forward () is implemented as above, you can call it without displaying the specified template parameter, and the template type parameter derivation mechanism will be inserted, as we have seen before, the derivation on T & will happen: when the real parameter called is the left value, T & will change to the left value. In outer (), when the names t1 and t2 are left values, we also need to change them to the right value for forwarding. Using the above broken implementation, this function cannot be completed, and T & may be deduced by the compiler as the left value. Therefore, we use identity to prevent the intervention of the compiler's template parameter derivation mechanism. Programmers who often use templates should be familiar with this, because this completes the same job in C ++ 98/03 and C ++ 0x: typename identity <t> :: the colon in type is like a lead plate. The template type derivation of the compiler cannot traverse to its left. (Another topic is to explain its principles)

Move semantics: STD: Move () how it works

Now we have learned about the special rule in template type derivation and the reference degradation. Let's take a look at STD: Move ():

Template <typename T> struct removereference {
Typedef T type;
};

Template <typename T> struct removereference <t &> {
Typedef T type;
};

Template <typename T> struct removereference <t &> {
Typedef T type;
};

Template <typename T> typename removereference <t>: Type & move (T & T ){
Return T;
}

The implementation mechanism of removereference is the same as that of STD: remove_reference in the header file <type_traits> of C ++ 0x. For example, removereference <string >:: type, removereference <string & >:: type, and removereference <string & >:: type are both strings.

Similarly, the implementation mechanism of the move () and c ++ 0x header files <utility> is the same.

  • When move () is called by a string with the left value, t is inferred to be string &. Therefore, move () receives a string & type parameter (after the reference degrades), after removereference, the returned value is string &&.
  • When move () is called by a left value const string, t is inferred to be const string &, so move () receives a const string & type parameter (reference degraded ), after removereference, the returned value is const string &&.
  • When move () is called by a string with the right value, t is inferred to be a string, so move () receives a string & type parameter. After removereference, the return value is string &&.
  • When move () is called by a right value const string, t is inferred to be const string, so move () receives the const string & type parameter, after removereference, the returned value is const string &&.

This is the principle of converting the left value to the return value while STD: Move () is a constant attribute of the keep type.

Review

If you want to learn more about right-value references, you can read their proposals. It should be noted that the current situation may be different from the proposal. the right value reference has been incorporated into the C ++ 0x working paper and has been continuously improved. Some of the proposals are outdated, some are no longer correct, or they are not accepted by the C ++ 0x standard. But it still has great reference value.

N1377, n1385, and n1690 are the main drafts referenced by the right value. N2118 contains the final version of the draft that was included before C ++ 0x working paper. N1784, n1821, n2377, and n2439 record the evolution process of extending the move semantics to * this. It has become the C ++ 0x standard, but VC10 has not yet implemented it.

Outlook

N2812 "a security problem of right value reference (and how to solve it)" proposes to modify the initialization rule: Prohibit right value reference from binding to the left value. This will not affect the move semantics and perfect forwarding, so it will not invalidate the new technology you just learned (but it will lead to STD: Move () and STD: Forward () changes in implementation mode)

Stephen T. lavavej
Visual c ++ libraries developer

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.