In C ++ template, the typename and class keywords are used in many places, and they seem to be replaceable. Are these two keywords exactly the same?
I believe that the C ++ learner understands the class keyword very well. Class is used to define classes. After the C ++ template is introduced, the method for defining the template is as follows: template <class T> ......
Here, the class keyword indicates that T is a type. To avoid confusion between the use of class in these two places, the keyword typename is introduced, its function is the same as that of the class, indicating that the symbol behind it is a type, so that you can use the following method when defining the template: Template <typename T> ......
in the template definition syntax, the keyword class and typename play exactly the same role.
does typename only play a role in template definition? In fact, this is not the case. Another role of typename is to use the nested dependency type (nested depended name), as shown below:
class myarray
{< br> public:
typedef int lengthtype;
.....
}
Template <class T>
Void mymethod (T myarr)
{
Typedef typename T: lengthtype;
Lengthtype length = myarr. getlength;
}
At this time, the role of typename is to tell the C ++ compiler that the string after typename is a type name, not a member function or a member variable. If typename is not mentioned before, the compiler has no way to know whether T: lengthtype is a type or a member name (static data member or static function), so compilation fails.
DemoCode:
# Include <iostream>
Using namespace STD;
Template <typename T>
Int compare (const T & V1, const T & V2)
{
If (V1 <V2) Return-1;
If (V1> V2) return 1;
Return 0;
}
Int main (void)
{
Cout <"compare (1, 0):" <compare (1, 0) <Endl;
String S1 = "hi ";
String S2 = "world ";
Cout <"compare (" <S1 <"," <S2 <"):" <compare (S1, S2) <Endl;
Return 0;
}
Running result: Work@db-testing-com06-vm3.db01.baidu.com C ++] $./template compare (1, 0): 1 compare (HI, world):-1
========================================================== ========================================
Q: What are the differences between class and typename in the following template declarations (template declaration?
Template <class T> class widget; // uses "class" Template <typename T> class widget; // uses "typename" |
Answer: There is no difference. When declaring a template type parameter (template type parameter), class and typename mean the same thing. SomeProgramMembers prefer to use class at all times because it is easier to input. Others (including myself) prefer typename because it implies that this parameter does not have to be a class type ). A few developers use typename when any type is allowed, while retaining the class to only accept user-defined types (user-defined type. However, from the perspective of C ++, class and typename mean the same thing when declaring a template parameter (Template parameter.
However, C ++ does not always regard class and typename as equivalent. Sometimes you must use typename. To understand this, we have to discuss the two names involved in a template.
Suppose we have a function template that can obtain an object that can be assigned to ints in STL-compatible container (STL compatible container. Further assume that this function simply prints the value of its second element. It is a confused function implemented in a confused way, and as I wrote below, it cannot even be compiled, but please put these aside beforehand-there is a way to discover my stupidity:
Template <typename C> // print 2nd element in Void print2nd (const C & container) // container; { // This is not valid C ++! If (container. Size ()> = 2 ){ C: const_iterator ITER (container. Begin (); // get iterator to 1st Element + ITER; // move ITER to 2nd Element Int value = * ITER; // copy that element to an int STD: cout <value; // print the int } } |
I highlight two local variables (local variables), ITER and value in this function. The ITER type is C: const_iterator, a type dependent on Template parameter (Template parameter) C. The name of a template that depends on a template parameter (Template parameter) is called dependent names (dependency name ). When a dependent names (dependency name) is nested inside a class, I call it nested dependent name (nested dependency name ). C: const_iterator is a nested dependent name (nested dependency name ). In fact, it is a nested dependent type name (nested dependency type name), that is, a nested dependent name (nested dependency name) involving a type ).
Another local variable (local variable) value in print2nd has the int type. Int is a name that does not depend on any template parameter (Template parameter. Such a name is famous for its non-dependent names. (I cannot figure out why they do not call it independent names (no dependency name ). If, like me, you find that the term "non-dependent" is an annoying thing and you resonate with me, but "non-dependent" is the term of this type of name, so, like me, turn your eyes and give up your self-claim .)
Nested dependent name (nested dependency name) may cause parsing difficulties. For example, suppose we start print2nd:
Template <typename C> Void print2nd (const C & container) { C: const_iterator * X; ... } |
It seems that we declare X as a local variable (local variable) pointing to C: const_iterator ). But it only looks like this because we know that C: const_iterator is a type ). But what if C: const_iterator is not a type? What if C has a static data member (static data member) that happens to be called const_iterator? What if x happens to be the name of a global variable (global variable? In this case, the above Code is not to declare a local variable (local variable), but to be C: const_iterator multiplied by X! Of course, it sounds silly, but it is possible, and the person who writes the C ++ parser must consider all possible input, or even stupid.
Until C becomes known, there is no way to know whether C: const_iterator is a type (type), and C is not known when the template (Template) print2nd is parsed. C ++ has a rule to solve this ambiguity: If the parser encounters a nested dependent name (nested dependency name) in a template ), it assumes that the name is not a type unless you tell it in other ways. By default, nested dependent name (nested dependency name) is not types (type ). (For this rule, I will tell you later .)
Remember this and look at the beginning of print2nd:
Template <typename C> Void print2nd (const C & container) { If (container. Size ()> = 2 ){ C: const_iterator ITER (container. Begin (); // This name is assumed ... // Not be a type |
This is why C ++ is not legal and should be clear now. ITER's declaration (Declaration) makes sense only when C: const_iterator is a type, but we didn't tell C ++ that it is, c ++ assumes that it is not. To change this situation, we must tell C ++ C: const_iterator that it is a type ). We put typename in front of it to do this:
Template <typename C> // This is valid C ++ Void print2nd (const C & container) { If (container. Size ()> = 2 ){ Typename C: const_iterator ITER (container. Begin ()); ... } } |
General rules are simple: when you involve a nested dependent type name (nested dependency type name) in the template, you must place the word typename next to it. (I will describe an exception later .)
Typename should only be used to identify nested dependent type name (nested dependency type name); other names should not be used. For example, this is a function template that obtains an iterator (iterator) of a container (container) and the container (container ):
Template <typename C> // typename allowed (as is "class ") Void F (const C & container, // typename not allowed Typename C: iterator ITER); // typename required |
C is not a nested dependent type name (nested dependency type name) (it is not nested inside something dependent on a template parameter (Template parameter ), therefore, when declaring the container, it does not have to be prefixed by typename, but C: iterator is a nested dependent type name (nested dependency type name), so it must be prefixed by typename.
"Typename must precede nested dependent type names" ("typename must be prefixed with nested dependency type names") The exception is that typename does not have to be prefixed in a list of base classes (base class list) or in a member initialization list (member initialization list) as a base classes identifier (base class identifier) of the nested dependent type name (nested dependency type name ). For example:
Template <typename T> Class derived: public base <t >:: nested { // Base class list: typename not Public: // allowed Explicit derived (int x) : Base <t>: Nested (x) // Base Class Identifier in MEM { // Init. List: typename not allowed
Typename base <t >:: nested temp; // use of nested Dependent Type ... // Name not in a base class list or } // As a base class identifier in ... // Mem. init. List: typename required }; |
Such a conflict is annoying, but once you get some experience in your experience, you almost don't care about it.
Let's take a look at the last typename example, because it is representative in the real code you see. Suppose we are writing a function template to get an iterator (iterator), and we need to make a partial copy of the object (object) pointed to by the iterator (iterator) temp, we can do this:
Template <typename itert> Void workwithiterator (itert ITER) { Typename STD: iterator_traits <itert>: value_type temp (* ITER ); ... } |
Do not let STD: iterator_traits <itert>: value_type scare you. It is just the use of a standard traits class (standard feature class, the C ++ statement is "the type of thing pointed to by objects of Type itert" ("the type of the object pointed to by itert "). This statement declares a local variable (local variable) (temp) with the same type as the itert objects points to, and uses the object (object) pointed to by ITER) the temp is initialized. If the itert is vector <int >:: iterator, temp is the int type. If itert is list <string >:: iterator, temp is string type. Because STD: iterator_traits <itert>: value_type is a nested dependent type name (nested dependency type name) (value_type is nested inside iterator_traits <itert>, in addition, itert is a template parameter (Template parameter), which must be prefixed by typename.
If you think reading STD: iterator_traits <itert>: value_type is annoying, think of the same thing as it to represent it. If you are afraid of inputting it multiple times like most programmers, you need to create a typedef. For traits Member names (feature member name) such as value_type, a general convention is that typedef name is the same as traits member name, so such a local typedef is usually defined as follows:
Template <typename itert> Void workwithiterator (itert ITER) { Typedef typename STD: iterator_traits <itert >:: value_type;Value_type temp (* ITER ); ... } |
Many programmers initially found that "typedef typename" is not harmonious, but it is a reasonable incidental result involving the nested dependent type names (nested dependency type name) rule. You will get used to it quite quickly. After all, you have powerful motives. How long does it take to enter typename STD: iterator_traits <itert>: value_type?
In conclusion, I should mention the differences between the compiler and the compiler on the execution of rules around typename. Some compilers accept the code that is missing when typename is required; Some compilers accept the code that exists when typename is not allowed; and a few (usually old) it rejects typename from appearing where it is required. This means that the interaction between typename and nested dependent type names (nested dependency type name) may cause some minor portability problems.
Things to remember
· When template parameters is declared, class and typename are interchangeable.
· Use typename to identify nested dependent type names (nested dependency type name), in base class lists (base class list) or in a member initialization list (member initialization List) is used as a base Class Identifier (base class identifier.
Reference: http://dev.yesky.com/13/2221013.shtml (C ++ proverbs)
Reference: http://blog.csdn.net/zhulimin/archive/2008/03/26/2218299.aspx (C ++ template)