Typename in the C ++ Template

Source: Internet
Author: User
Tags traits

I recently wrote a small item and encountered an error in the template. It was very interesting and wrong.CodeAs follows:

1 # Include <iostream>
2 # Include < Set >
3 Using Namespace STD;
4
5 Template < Class T>
6 Void Set2str ( Set <T> inset)
7 {
8 // Typename T: iterator itset;
9 Set <T>: iterator itset;
10 }
11
12
13 Int Main ( Int Argc, Char Const * Argv [])
14 {
15 Set <Int >;
16 Set2str < Int > ();
17
18 Return 0 ;
19 }

The error message is as follows:

1 . Cpp: In function' Void Set2str (STD :: Set <T, STD: less <_ key>, STD: Allocator <_ chart>) ' :
1 . Cpp: 9 : Error: Expected '; ' Before "itset"
1 . Cpp: In function' Void Set2str (STD :: Set <T, STD: less <_ key>, STD: Allocator <_ chart>) [with T = Int ] ' :
1 . Cpp: 16 : Instantiated From Here
1 . Cpp: 9 : Error: dependent-name 'std :: Set <T, STD: less <_ key>, STD: Allocator <_ chart> >:: iterator ' Is parsed as a non-type, but instantiation yields a type
1 . Cpp: 9 : Note: Say 'typename STD :: Set <T, STD: less <_ key>, STD: Allocator <_ chart> >:: iterator ' If a type is meant

Attention: "XXX,Is parsed as a non-type, but instantiation yields a type", This is the cause of the error. In fact, the solution has been provided below," Say 'typename' xxxIf a type is meant". Add typename. Just like the above comment.

 

For more information, see the following URL.

Http://www.michael-hammer.at/blog/type_or_non-type/

Http://blog.csdn.net/dick_china/article/details/4522253

 

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.

 

 

 

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.