13.2. Template Functions

In general, a template is a pattern or model. An example of a template is a (word processing) file that contains the basic format of a specialized document that writers use as a starting point. We use the template by filling in some specific or missing information. A C++ template function similarly provides a function's basic pattern or format. We can use the function by providing (a) any unspecified data types and (b) any data values (i.e., function arguments).

For example, suppose that we need to write a swap function that swaps the values stored in two variables (this task is a vital sub-operation used by functions that sort data stored in an array). It would be nice if our function worked with all arrays regardless of the kind or type of data stored in the array. Based on C++ templates, we can write and use a general, type-independent swap function as illustrated in Figure 1:

template <class T>
void swap(T& x, T& y)
{
	T temp = x;
	x = y;
	y = temp;
}
template <typename T>
void swap(T& x, T& y)
{
	T temp = x;
	x = y;
	y = temp;
}
double	data[1000];
	. . .
swap(data[i], data[j]);
	. . .
person	people = new person[100];
	. . .
swap(people[x], people[y]);
(a)(b)(c)
Defining and calling a template-based swap function. It is traditional to use a capital T to represent the template variable when there is only one. T is a placeholder for some general, yet-to-be-determined data type. The data type is determined later when the user calls the function, at which time the T in the function is replaced by the specific data type derived from the variables used in the function call. The syntax highlighted in yellow represents "boiler plate" code that is always present (it is the code that the C++ designers chose to use to introduce the template mechanism).
  1. The original syntax, which still works, used the keyword class to introduce the template variable
  2. Newer syntax also allows the keyword typename to introduce the template variable because any data type, not just class names, can replace T
  3. The compiler determines from the function calls that the arguments are type double in the first call and are type person in the second call (where person presumably names a class or structure).

Template functions share another important connection with parameterized macros: we must wait until the type substitution is complete before compiling them. It is impossible to compile template functions and store the object code in a system library like sqrt and pow. That doesn't mean that we can't or don't have libraries of template functions, but it does mean that template functions are provided as source code.

C++ libraries put template function source code in a header file, programmers include it with "normal" source code, and the compiler processes it following the type expansion or substitution. Furthermore, the compiler expands the template source code for each data type used with a template function. So, a program contains one copy of the code for each data type that the program needs the function to support. For example, Figure 1(b) shows the swap function used with both an array of integers and an array of person objects. In the first example, int replaces the function template variable, and in the second example, the class name person replaces the function template variable. Each replacement results in a separate copy of the swap function source code with int and person replacing the template variable T respectively.

<algorithm>: The Template Function Library

C++ does provide a rich set of template functions, which are contained in the <algorithm> header file. The min function (near the bottom of the list) is just one of many template functions C++ programmers may utilize. The complexity and flexibility of these functions have steadily increased since their introduction with the ANSI 1998 C++ standard. For example, two simple but quite useful versions of the min template function are:

template <class T> const T& min (const T& a, const T& b);
template <class T, class Compare> const T& min (const T& a, const T& b, Compare comp);

The first function "assumes" that the type replacing T supports the < operator. So, if a class replaces T, the class must overload operator<. Figures 2 and 3 demonstrate this version of min. The second version of min uses an external comparator, which may be either a function pointer (demonstrated in Figure 4) or a function object (demonstrated in Figure 5).

Examples

#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
	int	x = 20;
	int	y = 10;

	cout << min(x, y) << endl;

	return 0;
}
The min template function used with a built-in data type. The template function min, extracted from the <algorithm> header file, detects that both arguments are type int and so returns a value of type int. The < operator is naturally defined for integer values.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

class employee
{
private:
	string	name;
	int	id;
public:
	employee(string n, int i) : name(n), id(i) {}
	friend	bool	 operator<(const employee& e1, const employee& e2) { return e1.name < e2.name; }
	friend	ostream& operator<<(ostream& out, employee& me)
	{
		out << me.name << "\t" << me.id;
		return out;
	}
};

int main()
{
	employee	e1("Dilbert", 123);
	employee	e2("Alice", 987);

	//cout << min(e1, e2) << endl;		// doesn't work
	employee	e3 = min(e1, e2);
	cout << e3 << endl;

	return 0;
}
The min template function used with a class with operator<. The employee class has two member variables, which means that there are two ways to order or compare two employee objects: alphabetically ("ACIIbetically," really) or by id number. However, a class may only define one overloaded operator<, providing only one ordering or comparison. The overloaded operator< illustrated here compares the two employees by name. Notice that in this example that the min function is not "smart" enough to determine the return type without help; this failure is illustrated by the cout statement that is commented out. In the following cout statement, the min function determines its return type based on the the assignment operation.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

class employee
{
private:
	string	name;
	int	id;
public:
	employee(string n, int i) : name(n), id(i) {}
	friend	bool	 comp1(const employee& e1, const employee& e2) { return e1.name < e2.name; }
	friend	bool	 comp2(const employee& e1, const employee& e2) { return e1.id < e2.id; }
	friend	ostream& operator<<(ostream& out, employee& me)
	{
		out << me.name << "\t" << me.id;
		return out;
	}
};

int main()
{
	employee	e1("Dilbert", 123);
	employee	e2("Alice", 987);

	employee	e3 = min(e1, e2, comp1);
	cout << e3 << endl;

	employee	e4 = min(e1, e2, comp2);
	cout << e4 << endl;

	return 0;
}
The min template function used with a class type and with function pointers. As in the previous figure, the employee class has two member variables. Programs can order employee objects by name or id number, depending on which comparison function they use. However, in this example, a three-argument version of the min function allows the programmer to pass a pointer to an ordering function as the third function argument. The employee class defines two ordering functions: comp1 orders two employee objects by name, while comp2 orders employee objects by id number. In some situations, it is possible to define a comparison function that takes an argument and that allows the programmer to select the desired ordering.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

class employee
{
private:
	string	name;
	int	id;
public:
	employee(string n, int i) : name(n), id(i) {}
	string	getName() const { return name; }
	friend	ostream& operator<<(ostream& out, employee& me)
	{
		out << me.name << "\t" << me.id;
		return out;
	}
};

class CompareName
{
public:
	bool operator() (const employee& e1, const employee& e2) { return e1.getName() < e2.getName(); }
};

int main()
{
	CompareName	c1;
	employee	e1("Dilbert", 123);
	employee	e2("Alice", 987);

	employee	e3 = min(e1, e2, c1);
	cout << e3 << endl;

	return 0;
}
The min template function used with a class and a comparator or function object. A Function object, or functor is an object that can be called like a function. If the object is an instance of a class that overrides operator(), the functor is called with the "normal" function syntax with zero or more arguments. In this example, an instance of the CompareName class is created and passed as the third argument to the min function. c1 is a functor that compares or orders two employee objects by name; we could also create a new functor class that compares employee objects by id. The CompareName is similars to Java's generic util.Comparator interface.