Templates

A data type (char *) that requires special handling

  1. Before they invented string objects, the characters of a string were stored in memory, and pointer pointed to the first character of the string.
    For example, the pointer p points to the h in hello.
    1. charstar.C, charstar.txt

The min function

  1. Here is a set of functions in main.C that should be written as a single template function.
    The C++ Standard library already has a function named min whose full name is std::min because it belongs to the standard namespace std.
    The full name of my min functions is ::min, because they do not belong to any namespace.
    I wrote ::min to make sure I was calling my own min functions, not the one in the standard library.

    To get the expression b < a to compile when b and a are of data type const date&, we had to define the functions operator< or operator int for class date.

    	if (b < a) {       //if operator<(b, a) {
    
    	if (b < a) {       //if (b.operator int() < a.operator int()) {
    
    1. date.h: a very simple class date, just enough to make the main function work.
    2. date.C
    3. main.C, main.txt
    c++ main.C date.C
    
  2. Let’s declare and define a function template in main.C that will work for every data type except const char *.

    The first three calls to min in the main function create three instantiations of the function template.
    In the three instantiations, the computer deduces that the T should be changed to int, double, const date& respectively.
    (An instantiation is also called an implicit specialization.)

    The T is called a template argument.
    As usual, the a and b are called function arguments.
    And the 10 and 20 are the actual function arguments.

    1. date.h: exactly the same class date as in the previous example.
    2. date.C
    3. main.C, main.txt: exactly the same main function as in the previous program, but the rest of main.C is different.
    c++ main.C date.C
    
  3. Combine the function declarations and definitions in main.C.
    1. date.h: exactly the same class date as in the previous example.
    2. date.C
    3. main.C, main.txt: exactly the same main function as in the previous example, but the rest of main.C is different.
    c++ main.C date.C
    
  4. Move the function declarations and definitions to a .h (header) file.
    1. min.h contains the declarations and definitions of the min template function. See the important comment about the data type T.
    2. date.h: exactly the same class date as in the previous example.
    3. date.C
    4. main.C, main.txt: exactly the same main function as in the previous example, but the rest of main.C is different.
    c++ main.C date.C
    
    10
    2.71
    5/1/2025
    goodbye
    
    See this min.h for a better version that passes function arguments of type T by reference, i.e., as a const T&.
    Ths shows that the data type of a function argument can be more than just a plain unadorned T.
  5. The min in the C++ Standard Library does not know that the data type const char * probably needs to be handled differently.
    1. date.h: exactly the same class date as in the previous example.
    2. date.C
    3. main.C, main.txt calls the min function in the C++ Standard Library.

The print function

  1. By default, when we output a double value, only 5 digits to the right of the decimal point are printed.
    To see all the digits, we must use the i/o manipulators fixed and setprecision.
    1. main.C, main.txt

  2. Combined to one function template:
    1. print.h
    2. main.C, main.txt

More than one template argument: T1 and T2

  1. Each print function has two arguments, which may be of different data types.
    1. date.h: exactly the same class date as in the previous example.
    2. date.C
    3. main.C, main.txt
    c++ main.C date.C
    
  2. A template function can have more than one template argument.
    1. print.h contains the template
    2. date.h: exactly the same class date as in the previous example.
    3. date.C
    4. main.C, main.txt
    c++ main.C date.C
    

A local variable of type T

  1. Three different swap functions:
    1. date.h: exactly the same class date as in the previous example.
    2. date.C
    3. main.C, main.txt
    c++ main.C date.C
    
  2. A template function containing a local variable of type const T:
    1. date.h: exactly the same class date as in the previous example.
    2. date.C
    3. swap.h contains the template
    4. main.C, main.txt
    c++ main.C date.C
    
    #include <algorithm> for the C++ Standard Library swap.

An explicit template argument

  1. The second call to our min template will not compile, because our min template requires two actual arguments of the same data type.
    In this case, the computer is unable to deduce which data type, int or double, the T should turn into.
    1. min.h
    2. main.C
    c++ main.C
    
    main.C: In function ‘int main()’:
    main.C:14:22: error: no matching function for call to ‘min(int&, double&)’
       14 |         cout << ::min(i, d) << "\n";   //won’t compile
          |                 ~~~~~^~~~~~
    

    An explicit template argument is also required when the template function takes no function arguments at all.
    In this case, the return value of f<double> has one more correct digit than the return value of f<float>. That’s ten times as accurate!

    1. pi.C, pi.txt
    c++ -std=c++20 pi.C
    

A template class

  1. A class point with two double data members:
    1. point.h: member functions and friends, inline and not inline
    2. point.C
    3. main.C, main.txt
    c++ main.C point.C
    
  2. The same class point with float data members.
    On our machine storm.cis.fordham.edu, a float occupies only half as many bytes as a double.
    1. point.h: member functions and friends, inline and not inline
    2. point.C
    3. main.C, main.txt
    c++ main.C point.C
    
  3. A template class point.
    There is no more point.C file.
    1. point.h: member functions and friends, inline and not inline
    2. main.C, main.txt
    c++ main.C
    

A template class with a static member function

  1. Class counted is not a template class.
    It has a static member function named count which receives no invisible argument.
    1. counted.h
    2. counted.C
    3. main.C, main.txt
    c++ main.C counted.C
    
  2. Class numeric_limits is a template class with two static member functions, min and max.
    1. main.C, main.txt
    c++ main.C
    
    We will never create any object of classes numeric_limits<int>, numeric_limits<long>, etc.
    The only purpose of these classes is to give us information about the data types int, long, etc.
    Other examples of classes that give us information about other data types are char_traits and iterator_traits.

All the Standard Library container classes are template classes.

  1. Class vector is a template class.
    (See vectorint1.C and vectordouble1.C.)
    Ditto for classes list (loop.C), set, and pair (pair.C).
    1. main.C, main.txt
    c++ main.C
    
  2. Class map is a template class with two template arguments.
    1. map.C, map.txt
    c++ map.C
    

A numeric template argument

  1. Older C++ said typedef, but contemporary C++ says using.
    1. using.C, using.txt
    c++ using.C
    
  2. Each atom contains an array of electrons and an array of protons.
    Each row in the Periodic Table is called a period. The top row is period 1.
    1. hydrogen_atom.h
    2. helium_atom.h
    3. oxygen_atom.h
    4. main.C, main.txt
  3. Mass produce the elements with one template class.
    1. atom.h
    2. main.C, main.txt
  4. Hide the template with the keyword using. The person who makes a hydrogen object will never suspect that hydrogen is a template class.
    1. atom.h
    2. main.C, main.txt

Another numeric template argument

  1. An object of class zipcode5 contains a five-digit United States zipcode.
    1. zipcode5.h
    2. main.C, main.txt

  2. An object of class zipcode9 contains a nine-digit United States zipcode.
    1. zipcode9.h
    2. main.C, main.txt

  3. An object of class zipcode contains either a five-digit or nine-digit United States zipcode.
    1. zipcode.h
    2. main.C, main.txt

    If you habitually use only zipcode<5>, not zipcode<9>, you’ll want to say

    using zip = zipcode<5>;   //from now on, zip means zipcode<5>
    
    	zip z {"10458"};
    

Templates and Inheritance

  1. Remove the three nearly identical position-in-the foodchain classes (carnivore, herbivore, inert) from the last version of the game.
    Instead of #include’ing the three header files carnivore.h, herbivore.h, inert.h in the header files for the four grandchild classes wolf.h, rabbit.h, boulder.h, landmine.h, simply #include the following header file position.h in the header files for the four grandchild classes.
    1. position.h
    cc -DUNIX= -c term.c
    ls -l term.o
    
    c++ -o ~/bin/game4 main.C wabbit.C terminal.C term.o -lcurses
    ls -l ~/bin/game4
    
    game4
    
  2. Remove the four nearly identical grandchild classes wolf, rabbit, boulder, landmine from the game.
    Instead of #include’ing the two header files wolf.h and rabbit.h in main.C, simply #include the following header file grandchild.h in main.C.
    1. grandchild.h

    Invent another new class of grandchild called a looseCannon that moves randomly (like a rabbit) and has the appetite of a carnivore (like a wolf).
    On the screen, a loose cannon will appear as the character c.

    Have main.C create grandchildren of all these different classes.
    With the 3 motion and 3 rank classes we already have, we could easily create 3 × 3 = 9 classes of grandchildren.
    cc -DUNIX= -c term.c
    ls -l term.o
    
    c++ -o ~/bin/game5 main.C wabbit.C terminal.C term.o -lcurses
    ls -l ~/bin/game5
    
    game5
    

Templates and loops

  1. A template function that can loop through any type of array, vector, list, etc.
    1. loop.C, loop.txt

Strings are templates, too

  1. Plain old characters:
    1. cout.C, cout.txt

  2. Wide characters, for Chinese, Japanese, Greek, Russian, Hebrew, Arabic, etc.
    Lowercase w stands for “wide”; uppercase L stands for “long”.
    On our machine, a wide character oocupies 4 bytes (= 32 bits).
    Here’s the Unicode chart for Greek.
    1. wcout.C, wcout.txt

  3. Most users of wolf and rabbit do not suspect that these are now merely shorthands for different flavors of grandchild:
    using rabbit = grandchild<randomly, herbivore, 'r'>;
    using wolf   = grandchild<manual,   carnivore, 'W'>;
    
    Similarly, most users of the the familiar class string and its “wide” sibling wstring do not suspect that these have always been shorthands for different flavors of basic_string:
    using  string = basic_string<char>;
    using wstring = basic_string<wchar_t>;
    
    #include <string>
    
    	 string  s  {"hello"};
    	wstring ws {L"hello"};