Typename and typename in C ++
When the template parameter is declared, the prefix keywords class and typename can be exchanged;
Use keywordsTypename identifies the name of the nested subordinate typeBut does not need to be used in the base class list or member initialization list.
Dependent names: the name that appears in the template, dependent on a template parameter, such as T t;
Nested dependent names: the dependent name is embedded in the class, such as T: const_iterator ci;
Non-dependent names: does not depend on the name of any template parameter, such as int value;
If typename is not specified and the slave name is nested, parsing (parse) ambiguity may occur.
A nested subordinate type name is referenced in the template at any time. You need to add the keyword typename in the previous position;
Otherwise, an error (GCC): error: need 'typename' before 'T: xxx 'because' T' is a dependent scope
# Include <iostream> # include <string> # include <vector> using namespace std; template <typename T> void print2nd (const T & container) {typename T :: const_iterator iter (container. begin (); // If typename is not added, the error + + iter; int value = * iter; std: cout <value;} int main () is returned () {vector <int> vi = {1, 2, 3, 4, 5}; print2nd (vi); return 0 ;}
Exceptions:The name of the nested dependent type. If it is in the base class list and the member Initial Value column (member initialization list), typename is not used. Why not need it here? Because the compiler knows whether the type or variable is required here,(1) The Ken in the base class list is the type name, and (2) the Ken in the initialization list is the member variable name.
# Include <iostream> # include <vector> using namespace std; struct Number {Number (int x) {std: cout <"Number =" <x <std:: endl ;}; template <typename T> struct Base {typedef Number Nested ;}; template <typename T> class Derived: public Base <T> :: nested {// do not use typename public: explicit Derived (int x): Base <T >:: Nested (x) {// do not use typename Base <T> :: nested temp (7); // required}; int main () {Derived <int> d (5); return 0 ;}
When using a feature class, typename must be used, as shown in figure
# Include <array> # include <iostream> using namespace std; template <typename T> void workWithIter (T iter) {typedef typename std: iterator_traits <T >:: value_type; // use typename value_type temp (* iter); std: cout <"temp =" <temp <std: endl;} int main () {std :: array <int, 5> ai = {1, 2, 3, 4, 5}; std: array <int, 5 >:: iterator aiIter = ai. begin (); workWithIter (aiIter); return 0 ;}
Appendix:
// The second usage of typename is discussed below. Suppose we have a class: template <typename T> class Y {T: iterator * iter ;...}; /* we may want to define an iterator object. For example, if we use vector <int> to instantiate this template, iter should be an iterator pointer. However, if we use the following class to instantiate this template: */class cType {static int iterator ;...}; /* Then T: iterator * iter is interpreted by the compiler as a multiplication of two numbers. In fact, the C ++ compiler uses the second interpretation method, even if the iterator is indeed a type name. To avoid this conflict, when we apply the qualified dependent name, we need to use typename to indicate that this is a type name. that is: */template <typename T> class Y {typename T: iterator * iter; typedef typename T: iterator; // defines Y :: iterator type name ...}; // typename indicates that the following name is a type