CSC262 Feb10

slide version

single file version

Contents

  1. 1. C++ template functions and template classes
  2. 1.1 Template Function Example
  3. 1.2 Convert this to valid C++ code:
  4. 1.3 Compilation is different with templates
  5. 1.4 Using the template function simplesort:
  6. Exercise: Declare and write the template function printArray
  7. 2.0 All function members of template classes are template functions
  8. 2.1.1 Example (non-template)
  9. 2.1.2 Example
  10. 2.2 Template Classes
  11. 2.3 Template version of intArray
  12. 2.4 The template version of intArray
  13. Template class Member Implementations
  14. 2.5 Example (template version)
  15. 2.6 Example (same template version; different element type)
  16. Template Caveats

1. C++ template functions and template classes[1] [top]

C++ lets you declare and use a special kind of variable whose value is a type name or expression

The syntax for declaring such a variable is:

	template <typename T>
      

This declares T to be a variable whose value can be a type name or expression.

An alternate syntax is often used:

	template <class T>	
      

but the value of T can be type expressions like int or Point or int *

That is, the value of T does not have to a type that is the name of a class.

1.1 Template Function Example[2] [top]

Write a simple function to sort an array of elements of type T:



void simplesort(T a[], int n)
{
  int maxpos;
  for(int i = n; i > 1; i--) {
    maxpos = 0;
    for(int j = 1; j < i; j++) {
      if ( a[maxpos] < a[j] ) {
	maxpos = j;
      }
    }
    T tmp = a[maxpos];
    a[maxpos] = a[i-1];
    a[i-1] = tmp;
  }
}

1.2 Convert this to valid C++ code:[3] [top]

#ifndef SIMPLESORT_H
#define SIMPLESORT_H

template <class T>
void simplesort(T a[], int n)
{
  int maxpos;
  for(int i = n; i > 1; i--) {
    maxpos = 0;
    for(int j = 1; j < i; j++) {
      if ( a[maxpos] < a[j] ) {
	maxpos = j;
      }
    }
    T tmp = a[maxpos];
    a[maxpos] = a[i-1];
    a[i-1] = tmp;
  }
}
#endif

1.3 Compilation is different with templates[4] [top]


a. The code above is in simplesort.h (there is no simplesort.cpp!)

b. If we tried to compile this code by itself, it is incomplete. What
type will be subtituted for the parameter T?

c. We can use almost any type for T. ALMOST.

1.4 Using the template function simplesort:[5] [top]

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <string>
#include "simplesort.h"

using namespace std;

int main()
{
  int a[] = {5,2,3,10,7,1,4,8,9,6};
  int n = sizeof(a)/sizeof(int);

  simplesort(a, n); // compiler replaces T by int
  printArray(a, n);

  double b[] = {0.5,0.2,0.3,0.7,0.1,0.4,0.8,0.9,0.6};
  int nd = sizeof(b)/sizeof(double);

  simplesort(b, nd); // Compiler replaces T by double
  printArray(b, nd);

  string c[] = {"bb", "aa", "cb", "ca", "ba", "cd", "ab", "ac"};
  int ns = sizeof(c)/sizeof(string);

  simplesort(c, ns); // Compiler replaces T by string
  printArray(c, ns);

  return 0;
}

sizeof(a) is 40  (10 int's, each of size 4)
sizeof(int) is 4

sizeof(a)/sizeof(int) is 10  (the number of int's in a)

Exercise: Declare and write the template function printArray[6] [top]

 



    

2.0 All function members of template classes are template functions[7] [top]



template <class T>
class Pair
{
public:
 Pair();
 Pair(const T& xval, const T& yval);
 T getFirst();
 T getSecond();
 
private:
 T x;
 T y;
};


template <class T>
T Pair<T>::getFirst()
{
  return x;
}

T Pair&T>::getSecond()
{
  return y;
}

2.1.1 Example (non-template)[8] [top]

The intArray class. intArray's grow automatically unlike ordinary arrays.


#ifndef INTARRAY_H
#define INTARRAY_H

#include <iostream>

using namespace std;


class intArray
{
  int *arr;
  int arr_size;
  int arr_capacity;
  void grow(int new_capacity);
public:
  intArray();
  intArray(int sz);
  intArray(const intArray& other); // 1. copy constructor

  int& at(int i);
  const int& at(int i) const;
  void add(int x);

  void operator=(const intArray& other); // 2. assignment

  int size() const;
  ~intArray();  // 3. destructor
};

#endif

2.1.2 Example[9] [top]

int main()
{
  // declare an empty intArray (of integers)
  intArray a;
  
  // Insert numbers at the end
  for(int i = 0; i < 10000; i++) {
    a.add(i);
  }

  // Print the items in the Array a

  for(int i = 0; i < a.size(); i++) {
     cout << a.at(i) << endl;
  }

  return 0;
}
 

2.2 Template Classes[10] [top]

Our intArray class has int as the type of array elements.

If we wanted a intArray with a different type, we would have to change the int type to the new different type, but otherwise there would be no change to the code.

For example we might want a array of LineItem's. So the substitute for the int data type would be: LineItem.

2.3 Template version of intArray[11] [top]

If we created the new intArray for LineItem data, we would have a naming problem. We would have to create a name like

Instead of doing that, we can write the code once for a class named Array, but add a type "parameter".

When the Array is created, we provide a type name or expression for this parameter. For example:

 Array<int>  arr1;      // Array of integers
 Array<LineItem> arr2;   // Array of LineItem's

2.4 The template version of intArray[12] [top]


#ifndef ARRAY_H
#define ARRAY_H

#include <iostream>

using namespace std;

template <class T>
class Array
{
  T *arr;
  int arr_size;
  int arr_capacity;
  void grow(int new_capacity);
public:
  Array();
  Array(int sz);
  Array(const Array& other); // 1. copy constructor

  T& at(int i);
  const T& at(int i) const;
  void add(const T& x);

  void operator=(const Array& other); // 2. assignment

  int size() const;
  ~Array();  // 3. destructor
};
    

Template class Member Implementations[13] [top]

The member functions, constructors, destructors of a template class should be implemented in the .h file rather than a .cpp file.



#ifndef ARRAY_H
#define ARRAY_H

#include <iostream>

using namespace std;

template <class T>
class Array
{
  ...
};

// Add all the member function implementations here!
// after the class declaration.

template <class T>
Array<T>::Array()
{
  arr_size = 0;
  arr_capacity = 10;
  arr = new T[arr_capacity];
}
...

template <class T>
void Array<T>::add(const T& x)
{
  if ( arr_size == arr_capacity ) {
     grow(2*arr_capacity);
  }
  arr[arr_size] = x;
  arr_size++;
}

#endif

2.5 Example (template version)[14] [top]

int main()
{
  // declare an empty Array (of integers)
  Array<int> a;
  
  // Insert numbers at the end
  for(int i = 0; i < 10000; i++) {
    a.add(i);
  }

  // Print the items in the Array a

  for(int i = 0; i < a.size(); i++) {
     cout << a.at(i) << endl;
  }

  return 0;
}
 

2.6 Example (same template version; different element type)[15] [top]

int main()
{
  // declare an empty Array (of Point's)
  Array<Point> a;
  int x, y;

  srand((unsigned int) time(0)); // Initialize random number generator

  // Insert random Point's at the end
  for(int i = 0; i < 10000; i++) {
    x = rand();
    y = rand();
    a.add( Point(x,y) );
  }

  // Print the Points in the Array a
  // Assumes operator<< has been overloaded for Poitn

  for(int i = 0; i < a.size(); i++) {
     cout << a.at(i) << endl;
  }

  return 0;
}
 

Template Caveats[16] [top]