You might find function overloading fascinating, but you shouldn’t overuse it. You should reserve function overloading for functions that perform basically the same task but with different forms of data. Also you might want to check whether you can accomplish the same end by using default arguments. For example, you could replace the single, string-oriented left()
function with two overloaded functions:
char * left(const char * str, unsigned n); // two arguments
char * left(const char * str); // one argument
But using the single function with a default argument is simpler. There’s just one function to write instead of two, and the program requires memory for just one function instead of two. If you decide to modify the function, you have to edit only one. However, if you require different types of arguments, default arguments are of no avail, so in that case, you should use function overloading.
Contemporary C++ compilers implement one of the newer C++ additions: function templates. A function template is a generic function description; that is, it defines a function in terms of a generic type for which a specific type, such as int
or double
, can be substituted. By passing a type as a parameter to a template, you cause the compiler to generate a function for that particular type. Because templates let you program in terms of a generic type instead of a specific type, the process is sometimes termed generic programming. Because types are represented by parameters, the template feature is sometimes referred to as parameterized types. Let’s see why such a feature is useful and how it works.
Earlier Listing 8.4 defined a function that swapped two int
values. Suppose you want to swap two double
values instead. One approach is to duplicate the original code but replace each int
with double
. If you need to swap two char
values, you can use the same technique again. Still, it’s wasteful of your valuable time to have to make these petty changes, and there’s always the possibility of making an error. If you make the changes by hand, you might overlook an int
. If you do a global search-and-replace to substitute, say, double
for int
, you might do something such as converting
int x;
short interval;
to the following:
double x; // intended change of type
short doubleerval; // unintended change of variable name
C++’s function template capability automates the process, saving you time and providing greater reliability.
Function templates enable you to define a function in terms of some arbitrary type. For example, you can set up a swapping template like this:
template <typename AnyType>
void Swap(AnyType &a, AnyType &b)
{
AnyType temp;
temp = a;
a = b;
b = temp;
}
The first line specifies that you are setting up a template and that you’re naming the arbitrary type AnyType
. The keywords template
and typename
are obligatory, except that you can use the keyword class
instead of typename
. Also you must use the angle brackets. The type name (AnyType
, in this example) is your choice, as long as you follow the usual C++ naming rules; many programmers use simple names such as T
, which, one must admit, is simple indeed. The rest of the code describes the algorithm for swapping two values of type AnyType
. The template does not create any functions. Instead, it provides the compiler with directions about how to define a function. If you want a function to swap int
s, then the compiler creates a function following the template pattern, substituting int
for AnyType
. Similarly, if you need a function to swap double
s, the compiler follows the template, substituting the double
type for AnyType
.
Before the C++98 Standard added the keyword typename
to the language, C++ used the keyword class
in this particular context. That is, you can write the template definition this way:
template <class AnyType>
void Swap(AnyType &a, AnyType &b)
{
AnyType temp;
temp = a;
a = b;
b = temp;
}
The typename
keyword makes it a bit more obvious that the parameter AnyType
represents a type; however, large libraries of code have already been developed by using the older keyword class
. The C++ Standard treats the two keywords identically when they are used in this context. This book uses both forms so that you will be familiar with them when encountering them elsewhere.
You should use templates if you need functions that apply the same algorithm to a variety of types. If you aren’t concerned with backward compatibility and can put up with the effort of typing a longer word, you can use the keyword typename
rather than class
when you declare type parameters.
To let the compiler know that you need a particular form of swap function, you just use a function called Swap()
in your program. The compiler checks the argument types you use and then generates the corresponding function. Listing 8.11 shows how this works. The program layout follows the usual pattern for ordinary functions, with a template function prototype near the top of the file and the template function definition following main()
. The example follows the more usual practice of using T
instead of AnyType
as the type parameter.
// funtemp.cpp -- using a function template
#include <iostream>
// function template prototype
template <typename T> // or class T
void Swap(T &a, T &b);
int main()
{
using namespace std;
int i = 10;
int j = 20;
cout << "i, j = " << i << ", " << j << ".
";
cout << "Using compiler-generated int swapper:
";
Swap(i,j); // generates void Swap(int &, int &)
cout << "Now i, j = " << i << ", " << j << ".
";
double x = 24.5;
double y = 81.7;
cout << "x, y = " << x << ", " << y << ".
";
cout << "Using compiler-generated double swapper:
";
Swap(x,y); // generates void Swap(double &, double &)
cout << "Now x, y = " << x << ", " << y << ".
";
// cin.get();
return 0;
}
// function template definition
template <typename T> // or class T
void Swap(T &a, T &b)
{
T temp; // temp a variable of type T
temp = a;
a = b;
b = temp;
}
The first Swap()
function in Listing 8.11 has two int
arguments, so the compiler generates an int
version of the function. That is, it replaces each use of T
with int
, producing a definition that looks like this:
void Swap(int &a, int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}
You don’t see this code, but the compiler generates and then uses it in the program. The second Swap()
function has two double
arguments, so the compiler generates a double
version. That is, it replaces T
with double
, generating this code:
void Swap(double &a, double &b)
{
double temp;
temp = a;
a = b;
b = temp;
}
Here’s the output of the program in Listing 8.11, which shows that the process has worked:
i, j = 10, 20.
Using compiler-generated int swapper:
Now i, j = 20, 10.
x, y = 24.5, 81.7.
Using compiler-generated double swapper:
Now x, y = 81.7, 24.5.
Note that function templates don’t make executable programs any shorter. In Listing 8.11, you still wind up with two separate function definitions, just as you would if you defined each function manually. And the final code doesn’t contain any templates; it just contains the actual functions generated for the program. The benefits of templates are that they make generating multiple function definitions simpler and more reliable.
More typically, templates are placed in a header file that is then included in the file using them. Chapter 9 discusses header files.
18.225.234.24