// Process a vector
vector
v.push_back(1);
v.push_back(2);
printSeq(v);
// Process a list
list
lst.push_back(3);
lst.push_back(4);
printSeq(lst);
} ///:~
Once again, without the typename keyword the compiler will interpret iterator as a static data member of Seq
Typedef-ing a typename
It’s important not to assume that the typename keyword creates a new type name. It doesn’t. Its purpose is to inform the compiler that the qualified identifier is to be interpreted as a type. A line that reads:.
typename Seq
causes a variable named It to be declared of type Seq
typedef typename Seq
Using typename instead of class
Another role of the typename keyword is to provide you the option of using typename instead of class in the template argument list of a template definition. To some, this produces clearer code (your mileage may vary):.
//: C05:UsingTypename.cpp
// Using 'typename' in the template argument list
template
int main() {
X
} ///:~
You probably won’t see a great deal of code that uses typename in this fashion, since the keyword was added to the language a relatively long time after templates were introduced.
Using the template keyword as a hint
Just as the typename keyword helps the compiler in situations in which a type identifier is not expected, there is also a potential difficulty with tokens that are not identifiers, such as the < and > characters; sometimes they represent the less-than or greater-than symbols, and sometimes they delimit template parameter lists. As an example, we’ll once more use the bitset class:.
//: C05:DotTemplate.cpp
// Illustrate the .template construct
#include
#include
#include
#include
using namespace std;
template
basic_string
return bs. template to_string
allocator
}
int main() {
bitset<10> bs;
bs.set(1);
bs.set(5);
cout << bs << endl; // 0000100010
string s = bitsetToString
cout << s << endl; // 0000100010
} ///:~
The bitset class supports conversion to string object via its to_string member function. To support multiple string classes, to_string is itself a template, following the pattern established by the basic_string template discussed in Chapter 3. The declaration of to_string inside of bitset looks like this:.
template
basic_string
Our bitsetToString( ) function template above allows you to request different types of string representations of a bitset. To get a wide string, for instance, you change the call to the following:
wstring s = bitsetToString
Note that basic_string uses default template arguments, so we don’t have to repeat the char_traits and allocator arguments in the return value. Unfortunately, bitset::to_string does not use default arguments. Using bitsetToString
The return statement in bitsetToString( ) contains the template keyword in an odd place—right after the dot operator applied to the bitset object bs. This is because when the template is parsed, the < character after the to_string token would be interpreted as a less-than operation instead of the beginning or a template argument list. We explain exactly why this confusion exists in the section "Name lookup issues" later in this chapter. The template keyword used in this context tells the compiler that what follows is the name of a template, causing the < character to be interpreted correctly. The same reasoning applies to the -> and :: operators when applied to templates. As with the typename keyword, this template disambiguation technique can only be used within a template.[50]
Member Templates
The bitset::to_string( ) function template is an example of a
template
class complex {
public:
template