A
In the template declaration, the two keywords of class and TypeName have exactly the same meanings
Template<class t> class Widget;template<typename t> class Widget;
Two
Template <typename c> void print2nd (const c& container) { if (container.size () >= 2) { C::const _iterator iter (Container.begin ()); ++iter; int value = *iter; Std::cout << value; } }
the type of ITER is c::const_iterator actually what must depend on the template parameter C. The name that appears within the template, if dependent on a template parameter, is called a subordinate name.
If the subordinate name is nested within class, it is called a nested subordinate name.
C::const_iterator is such a name nested subordinate name.
value type int. Does not depend on the name of any template parameter. Called a non-subordinate name
Nested subordinate names can cause difficulties in parsing:
Template <typename c> void print2nd (const c& container) { c::const_iterator* x;}
This is likely to be misunderstood! Misunderstood as multiplication sign!
Before we knew C, there was no way to know if C::const_iterator was a type. And when the compiler starts parsing template print2nd, it's not yet determined what C is.
C + + has a rule that resolves this ambiguous state: if the parser encounters a nested subordinate name in the template, it assumes that the name is not a type unless you tell it to. By default, the subordinate name is not a type. In addition, there is an exception.
So the above code is not a valid C + + code. We have to tell C + + that C::const_iterator is a type. Just place the keyword typename before you close it:
Template <typename c>//This legal C + + code void print2nd (const c& container) { if (container.size () >= 2) { C3/>typename C::const_iterator iter (Container.begin ()); ++iter; int value = *iter; Std::cout << value; } }
The exception to the rule that TypeName must be prefixed with the name of a nested subordinate type is that TypeName cannot appear in the base classes list until the nested subordinate type name is set. It is also not allowed as the base class modifier in the Member initialization list (member initialization lists) . For example:
The "typename" public is not allowed in the template <typename t> class Derived:public Base<t>::nested{//base class list: explicit Derived (int x) : base<t>::nested (x)//mem.init.list does not allow "typename" { typename base<t >::nested temp;//nested subordinate types are neither in the base class list nor in Mem.init.list, } //As a base class modifier, add typename};
Three
Let's look at a typename example: a function template that accepts an iterator and we intend to do a copy temp for the object that the iterator refers to:
Template <typename itert>void workwithiterator (itert) {TypeName Iterator_traits<itert>::value_type temp ( *iter);}
This is an application of the standard trait class (clause 47), which is equivalent to saying "the type of object referred to by the Itert". If Itert is vector<int>::iterator,temp type is int, if Itert is the type of list<string>::iterator,temp is string. Because Std::iterator_traits<itert>::value_type is a nested subordinate type name (Value_type is nested in iterator_traits<itert> Itert is a template parameter), so you must place the typename before it.
So long you're going to want to build a typedef. For traits member names such as Value_type, it is common practice to set the TypeDef name to represent a traits member name:
Template <typename itert> void Workwithiterator (Itert) { typedef typename std::iterator_traits<itert> :: Value_type value_type; Value_type temp (*iter); }
Please remember:
(1) When declaring the template parameter, the Prefix keyword class and typename are interchangeable.
(2) Use the keyword typename to identify nested subordinate type names, but not in base class lists (base class column) or member initialization list (Member initial column) with its base class modifier.
Effective C + +: Clause 42: Understanding the dual meaning of TypeName