Lecture 11: Template Functions and Template Classes


Template Functions

A relative new type of functions added to C++ are the template functions also known as either the generic functions or the function templates This function type addresses needs not handled by the other function types discussed above. There are times when it is desirable to create the same type of function over and over again. It would be nice for the programmer to tell the compiler how these functions are to be defined and then each time that type of function was called, the compiler would write the definition of the function needed for the data types involved. This is the roll played by template functions.

In order to create this type of function, the keywords: template and class are needed. While the word class is used, the code being used need not deal with classes. (The use of the word class was later changed to using the keyword: typename because using class caused confusion.) A simple construct for template functions is:

image from book

 template <class T> return_type functionName(signature) {    functionBody } 

image from book

T above need not be a class and can be any data type. T is really a place holder for the data type chosen by the programmer who implements the template function.

 Note:  Do not place any code between the first line listed above and the function definition. If you do, an error will occur.

The template function is like a blue print of a home created by an architect. When the program is compiled, the compiler then takes this blue print and writes a function for each different use of the template function. This process is referred to as an instantiation of the template function. For example:

image from book

 template <class T> T MAX(T value1, T value2) {   return ((value1 < value2) ? value2 : value1); } 

image from book

Using this template function definition, the following function calls could be used without the need to define more that this one function:

image from book

 int int3 = MAX(int1,int2); float float3 = MAX(float1, float2); double double3 = MAX(double1, double2); 

image from book

For each call, the compiler uses the template function definition listed above to write a definition for each of the calls. See maximum.cpp. In this program there are four different implementations of the template function. Each of these is called a specialization. The act of creating each function is called an instantiation. After you have run this program as is, notice that one of the lines of code is like the following:

image from book

 double double4 = MAX(double(int1),double); 

image from book

Observe that this line of code compiles and runs. However, if you remove the type casting and try to compile again, then the compile will fail for this type of instantiation. Why? Because this template function's definition requires that both arguments must be of the same data type.

The template function MAX() listed above could also have been defined as in the following:

image from book

 template <class T> T MAX(char *word,T value1, T value2) {   cout << word << endl;   return ((value1<value2)? value2:value1); } 

image from book

This template function is defined in maxmum2.cpp. Notice that the first argument can be a string (or any other data type could have been used here other that a pointer to a char) and the others can be some other data types.

When using template functions, the programmer is not restricted to only one data type. There can be several, some of which are specified in the original definition while others are not specified until the function call. The general construct of a template header is:

image from book

 template <type1 T1, type2 T2, ,typen Tn> 

image from book

In the line above the indicates that the number of different data types is not limited. Immediately below this header must be a function definition. The function definition must contain instances of the listed data types: T1 Tn. In addition to these data types, the definition may also contain other data types as well.

Not only may a template function have one argument from an unknown data type but it may have multiple unknown data types. For example the function MAX() could be defined as in the following:

image from book

 template <class T,class R> T MAX(char *word,T value1, T value2, R value3) {   T temp = ((value1<value2)? value2:value1);   cout << endl << endl << "-->> The word is " << word << endl;   if((R)temp < value3)      cout << "-->> The maximum is below the limit "           << value3 << endl;   return temp; } 

image from book

See maxmum3.cpp. Notice in this function that the classes R and T would have to have a type casting relationship with each other. This restriction is only required in this example because of the way the template function was defined. This is not a general requirement.

When looking at template functions for the first time, it seems strange to see the word class appear especially when the unknown data types need not be classes. This has been changed in Standard C++. The keyword typename replaces the keyword class in this case. For example the function MAX() from maxmum3.cpp could be changed to the following:

image from book

 template <typename T,typename R> T MAX(char *word,T value1, T value2,R value3) {   T temp = ((value1<value2)? value2:value1);   cout << endl << endl << "-->> The word is "        << word << endl;   if((R)temp < value3)        cout << "-->> The maximum is below the limit "             << value3 << endl;   return temp; } 

image from book

See maxmum4.cpp. Be careful in using the keyword: typename because not all compilers have implemented this keyword. The keyword typename will eventually be used with the declaration of data types not yet defined. Since this is the correct form for Standard C++, it is recommended that if your compiler recognizes the keyword typename then the keyword class should be dropped for template functions and it should be replaced with typename.

It might appear from these examples that only those data types that have a relational operator are candidates for template functions. That is not the case as the following definition shows.

image from book

 template <typename T> T power(T a, int exp) {    T base = 1;    while (exp-- > 0)      base = base * a;    return(base); } 

image from book

Calls to this template function could be:

image from book

 int numb1 = power(2, 5); float numb2 = power(3.56F, 3); complex numb3 = power(3+5i, 2); 

image from book

For an example of this function see: the_power.cpp.

There may be special programs where the template function defined in the program does not cover all cases. That is there may be some characteristic about a particular data type which does not fit into the template function definition. For example suppose you wanted to have powers of a string. Now the definition of the template function power() above does not permit this to happen. In this case you could define one instance where the power() function would do something different with one data type than it does with all other data types. For example you could define the following explicit specialization of the function power() which is an explicit overloading of a template function:

image from book

 string power(string a, int exp) {    string base = "";    while(exp-- > 0)      base = base + a;    return base; } 

image from book

These two definitions could be in the same program and this definition would overload the template function and hide it from the rest of the program. See the_power2.cpp. Notice how you could therefore have an instance of the power() function that takes a string to a power. For example:

image from book

 company = "SmallOne" string numb4 = power(company, 3); 

image from book

would give numb4 the value: " SmallOneSmallOneSmallOne ".

There is a newer way to implement an explicit overloading of a template function. The previous function could have been written as:

image from book

 template<> string power<string>(string a, int exp) {    string base = "";    while(exp-- > 0)      base = base + a;    return base; } 

image from book

For this example, see: the_power3.cpp. Notice that the only change between this example and the previous one was the redefinition of the explicit overloading of the template function.

In addition to having explicit instances of a template function to overload a particular template function, it is also possible to have several different template functions all with the same name and therefore overloading each other. For example, if the MAX() in each of the examples maxmum.cpp, maxmum2.cpp and maxmum3.cpp were all placed in the same program, they would all have the same name yet different signatures. They would therefore overload each other. See maxmum5.cpp

In the example: maxmum5.cpp there are three different versions of the template function MAX(). Is overloading template functions a good strategy? Further, notice that in some cases the examples appear to be cases where you could have just used overloaded functions instead of using template functions. The question might arise when should you use template functions, when should you use overloaded template functions and when should you just use overloaded functions? The answer to this question is like all such questions, it depends on the analysis of the program. However, if you have to write too many special cases of template functions, it might be the case where, overloading of functions would be a better solution. Further each instantiation of a template function must perform the same operations within the function while overloaded functions do not require this restriction.




Intermediate Business Programming with C++
Intermediate Business Programming with C++
ISBN: 738453099
EAN: N/A
Year: 2007
Pages: 142

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net