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 );
    }
}