10.8. Templates and Containers¶
- Templates enable us to specify a range of related (overloaded) functions-called function-template specializations-or a range of related classes-called class-template specializations.
- To use function-template specializations, the programmer writes a single function-template definition. Based on the argument types provided in calls to this function, C++ generates separate specializations to handle each type of call appropriately. These are compiled along with the rest of a program’s source code.
- All function-template definitions begin with the keyword template followed by formal type parameters to the function template enclosed in angle brackets ( and ); each formal type parameter must be preceded by keyword class or typename. Keywords class and typename used to specify function-template type parameters mean “any built-in type or user-defined type.”
- Template-definition formal type parameters are used to specify the kinds of arguments to the function, the return type of the function and to declare variables in the function.
- The name of a formal type parameter can be used only once in the type-parameter list of a template header. Formal type-parameter names among function templates need not be unique.
- A function template may be overloaded in several ways. We can provide other function templates that specify the same function name but different function parameters. A function template can also be overloaded by providing other non-template functions with the same function name, but different function parameters.
- Class templates provide the means for describing a class generically and for instantiating classes that are type-specific versions of this generic class.
- Class templates are called parameterized types; they require type parameters to specify how to customize a generic class template to form a specific class-template specialization.
- The programmer who wishes to use class-template specializations writes one class template. When the programmer needs a new type-specific class, the programmer uses a concise notation, and the compiler writes the source code for the class-template specialization.
- A class-template definition looks like a conventional class definition, except that it is preceded by template class T (or template typename T ) to indicate this is a class-template definition with type parameter T indicating the type of the class to create. The type T is mentioned throughout the class header and member-function definitions as a generic type name.
- Member-function definitions outside a class template each begin with template class T (or template typename T ). Then, each function definition resembles a conventional function definition, except that the generic data in the class always is listed generically as type parameter T. The binary scope-resolution operator is used with the class-template name to tie each member function definition to the class template’s scope.
- It is possible to use nontype parameters in the header of a class template.
- A class for a specific type can be provided to override the class template for that type.
- A class template can be derived from a class-template specialization. A class template can be derived from a non-template class. A class-template specialization can be derived from a class template. A non-template class can be derived from a class template.
- Functions and entire classes can be declared as friends of non-template classes. With class templates, the obvious kinds of friendship arrangements can be declared. Friendship can be established between a class template and a global function, a member function of another class (possibly a class-template specialization) or even an entire class (possibly a class-template specialization).
- Each class-template specialization instantiated from a class template has its own copy of each static data member of the class template; all objects of that specialization share that static data member. And as with static data members of non-template classes, static data members of class-template specializations must be initialized at file scope.
- Each class-template specialization gets a copy of the class template’s static member functions.
10.8.1. STL¶
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <list>
#include <algorithm> // for copy
using std::cout;
using std::endl;
using std::string;
template < class T >
void printList( const std::list< T > & listRef );
#define INITSIZE 2
char *ReadLine(char *, FILE *);
int linesize;
int main( int argc, char *argv[] )
{
char *line;
FILE *fp;
string *st;
std::list< string > top;
if( argc < 2 ) {
fp = stdin;
}
else {
if(( fp = fopen( argv[1], "r")) == NULL ) {
fprintf(stderr,"Error: could not open file %s\n", argv[1]);
exit(1);
}
}
linesize = INITSIZE;
if( (line = (char *)malloc(linesize*sizeof(char))) == NULL) {
fprintf( stderr, "Memory Allocation error.\n" );
exit(1);
}
/*
* Read data from file and insert into linked list
*/
while( (line = ReadLine(line, fp)) != NULL ) {
st = new string( line );
top.push_front( *st );
}
if( fp != stdin ) fclose( fp );
/*
* Sort the list
*/
top.sort();
/*
* print the sorted file.
*/
printList( top );
return 0;
}
char *ReadLine(char *buff, FILE *fp)
{
int c, i;
buff[0] = '\0';
buff[linesize - 1] = '\0'; /* mark end of buffer */
for( i = 0; ((c = fgetc(fp) ) != EOF) && (c != '\n'); i++ ) {
if( i == linesize - 1 ) {
linesize *= 2;
if( (buff = (char *)realloc(buff, linesize*sizeof(char))) == NULL) {
fprintf( stderr, "Memory Allocation error.\n" );
exit(1);
}
}
*(buff + i) = (char)c;
}
if( c == EOF && i == 0) return NULL;
*(buff + i) = '\0';
return buff;
}
template < class T >
void printList( const std::list< T > & listRef )
{
if( listRef.empty () )
cout << "List is empty";
else {
std::ostream_iterator< T > output( cout, "\n" );
std::copy( listRef.begin(), listRef.end(), output );
}
}