class Templates
class Templates
Structure:
12.1 Introduction
Objectives
12.2 Class Templates
Implementing a class template
Class template with multiple parameters
12.3 Function Templates
Implementing function templates
Using template functions
Function templates with multiple parameters
Overloading Function Templates
12.4 Template Instantiation
12.5 Class Template Specialization
Template class partial specialization
12.6 Template Function Specialization
12.7 Template Parameters
12.8 Static Members and Variables
12.9 Templates and Friends
12.10 Templates and Multiple – File Projects
12.11 Summary
12.12 Terminal Questions
12.13 Answers
12.1 Introduction
In the previous unit you have studied the methods to open and close files
along with the methods to check whether a file opening was successful or
not. You have also studied the I/O status flags, binary files and some very
useful functions in C++. In this unit you are going to study in detail about the
templates in C++. Template in C++ is newly added concept that enables us
to define generic classes and functions and hence provides support for
generic programming. Generic programming is an approach where generic
types are used as parameters in algorithms so that they work for variety of
suitable data types and data structures. We can use templates to create
family of class and functions. For example, a class template for an array will
}
int operator*(vector &y) //scalar product
{
int sum=0;
for( int i=0; i<size; i++)
sum= sum + this-> v[i] * y . v[i];
return sum;
}
};
The vector class can store an array of int numbers and perform the scalar
product of two int vectors as shown below:
int main()
{
int x[3] = {1, 2, 3};
int y[3] = {4, 5, 6};
vector v1(3); //creates a null vector of three integers
vector v2(3);
v1 = x; //creates v1 from the array x
v2= y;
int R = v1 * v2;
cout << “R = “ << R;
return 0;
}
Now let’s assume that we want to define a vector that can store an array of
float values. This can be done by replacing the appropriate int declarations
with float in the vector class. This means that the complete class needs to
be redefined.
This helps us define a vector class with the data type as a parameter and
then use this class to create a vector of any data type instead of defining a
new class every time. This can be achieved by using the templates.
12.2.1 Implementing a Class Template
As it has already been mentioned, the templates allow us to define generic
classes. It is a simple process to create a generic class using a template
with anonymous type. The general format of class template is as follows:
class classname
{
//class member specification with anonymous type T wherever
appropriate.
………….
};
For example, the definition of vector class is given below:
template<class T>
class vector
{
T* v; //type T vector
int size;
public:
vector(int m)
{
v= new T [ size = m];
for (int i=0; i<size; i++)
v[i]=0;
}
vector (T *a)
{
for(int i=0; i<size; i++)
v[i] = a[i];
}
T operator* (vector &y)
{
T sum = 0;
for (int i =0; i<size ; i++)
sum = sum + this -> v[i] * y. v[i];
return sum;
}
The class template definition is similar to an ordinary class definition except
the prefix template<class T> and the use of type T. This prefix tells the
compiler that a template is to be declared and T is used as a type name in
declarations. Thus vector has become a parameterized class with type T as
its parameter. T can be substituted with any data type including the user-
Manipal University Jaipur B2114 Page No.: 268
Object Oriented Programming – C++ Unit 12
T sum =0;
for (int i=0; i<size; i++)
sum = sum + this -> v[i] * y.v[i];
return sum;
}
};
int main()
{
int x[3] = {1, 2, 3};
int y[3] = {4, 5, 6};
vector <int> v1;
vector <int> v2;
v1 = x;
v2 = y;
int R = v1 * v2;
cout << “R =” << R << “\n”;
return 0;
}
The output of the above program will be:
R = 32
The following program shows the use of a vector class template for
performing the scalar product of float type vectors.
#include<iostream>
using namespace std;
const size = 3;
template <class T>
class vector
{
T* v; //type T vector
public:
vector()
{
v = new T[size];
for (int i=0; i<size; i++)
v[i] = 0;
}
vector (T* a)
{
for (int i=0; i<size; i++)
v [i] = a[i];
}
T operator*(vector &y)
{
T sum =0;
for (int i=0; i<size; i++)
sum = sum + this -> v[i] * y.v[i];
return sum;
}
};
int main()
{
float x[3] = {1.1, 2.2, 3.3};
int y[3] = {4.4, 5.5, 6.6};
vector <float> v1;
vector <float> v2;
v1 = x;
v2 = y;
int R = v1 * v2;
cout << “R =” << R << “\n”;
return 0;
}
The output of the above program will be:
R = 38.720001
{
………
……….
body of the class
…………
};
The program below shows the use of template class with two generic data
types.
#include<iostream>
using namespace std;
template< class T1, class T2>
class demo
{
T1 a;
T2 b;
}
public:
Test(T1 x, T2 y)
{
a=x;
b=y;
}
void show()
{
cout << a << “ and “ << b << “\n”;
}
};
int main()
{
demo <float, int> d1 (1.11, 567);
demo <int, char> d2 (200, ‘A’);
d1.show();
d2.show();
return 0;
}
The function template is similar to class template. We must use the template
parameter T as and when necessary in the function body and in its
argument list.
Function templates are implemented like regular functions, except they are
prefixed with the keyword template. Here is a sample with a function
template.
#include <iostream>
using namespace std;
//max returns the maximum of the two elements
template <class T>
T max(T a, T b)
{
return a > b ? a : b;
}
cout << "max(10, 15) = " << max(10, 15) << endl;
cout << "max('k', 's') = " << max('k', 's') << endl;
cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl;
}
Output:
max(10, 15) = 15
max('k', 's') = s
max(10.1, 15.2) = 15.2
12.3.3 Function templates with multiple parameters
Multiple parameters are supported by function templates. We can write a
function that compares three parameters and returns the largest of the
three. For example, in the program code shown below the function template
named findLargest(), returns the largest amongst the three parameters.
template <class T>
T findLargest(T x, T y, T z)
{
T max;
if( x > y)
max= x;
else
max = y;
if ( z> max)
max = z;
return max;
}
The three parameters are passed in the findLargest() function in the above
code. A temporary variable max is declared within this function. The data
type of max variable is the same as that of the function parameters. i.e., if
the three integers are passed to the function, then max is also an integer; if
three doubles are passed, then max is also of type double. If the first
parameter x passed to the findLargest() is larger than the second parameter
y, then x s assigned to max otherwise y is assigned to max. Then if the third
parameter z is larger than max, then z is assigned to max. And finally value
of max is returned. The variables x, y, z and max may be of any type for
which the greater than (>)operator and the assignment (+) operator have
been defined, but x, y, z and max must be of the same type because they
are all defined to be the same type named T.
12.3.4 Overloading Function Templates
Like ordinary functions it is possible to overload function templates. In this
section, we are going to discuss overloading when the templates are
involved. That is, you can have many function definitions with the same
function name so that when that name is used in function call, the C++
compiler decides which of the functions to be called.
Let us see the following program to understand the overloading of function
templates,
//maximum of two int values
int const& max (int const& a, int const& b)
{
return a < b ? b : a;
}
//maximum of two values of any type
template <typename>
T const& max (T const& a, T const& b)
{
return a < b ? b:a;
}
//maximum of three values of any type
template<typename T>
int main()
{
max(4, 5, 6); //calls the template for three arguments
max(8.1, 9,.1); //calls max<double> (by argument detection)
max (‘c’, ‘d’); // calls max<char> (by argument detection)
max(7,42) //calls the nontemplate for two ints
max< > (7, 42); //class max<int> (by argument deduction
Manipal University Jaipur B2114 Page No.: 276
Object Oriented Programming – C++ Unit 12
void g(){};
};
int main() {
Z<int>* p_zi; //instantiation of class Z<int> not required
Z<float>* p_zf; //instantiation of class Z<float> not required
return 0;
}
This time the compiler does not generate any definitions! There is no
need for any definitions. It is similar to declaring a pointer to an
undefined class or structure.
5. Consider the following sample. This is an example of implicit
instantiation of a function template.
//max returns the maximum of the two elements
template <class T>
T max(T a, T b)
{
return a > b ? a : b;
}
void main() {
int I;
I = max(10, 15); //implicit instantiation of max(int, int)
char c;
c = max('k', 's'); //implicit instantiation of max(char, char)
}
In this case the compiler generates functions max(int, int) and max(char,
char). The compiler generates definitions using the template function
max.
6. Consider the following sample. This is an example of explicit
instantiation of a function template.
template <class T>
void Test(T r_t) {
}
int main() {
//explicit instantiation of Test(int)
template void Test<int>(int);
return 0;
}
In this case the compiler would generate function Test(int). The compiler
generates the definition using the template function Test.
7. If an instantiation of a class template is required, and the template
declared but not defined, the program is ill-formed.
template <class T> class X ;
int main() {
X<int> xi;
return 0;
}
8. Instantiating virtual member functions of a class template that does not
require instantiation is implementation defined. For example, in the
following sample, virtual function X<T>::Test() is not required, VC5.0
generates a definition for X<T>::Test.
template <class T>
class X {
public:
virtual void Test() {}
};
int main() {
X<int> xi; //implicit instantiation of X<int>
return 0;
}
In this case the compiler generates a definition for X<int>::Test, even if it
is not required.
Self Assessment Questions
5. A class generated from a class template is called ________________.
6. Instantiating virtual member functions of a class template that does not
require instantiation is implementation defined. (True/False)
cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ;
cout << "max(\"Aladdin\", \"Jasmine\") = " << max("Aladdin",
"Jasmine") << endl ;
return 0 ;
}
Output:
max(10, 15) = 15
max('k', 's') = s
max(10.1, 15.2) = 15.2
max("Aladdin", "Jasmine") = Aladdin
Not quite the expected results! Why did that happen? The function call
max("Aladdin", "Jasmine") causes the compiler to generate code for
max(char*, char*), which compares the addresses of the strings! One can
use template specializations to correct special cases like these or to provide
more efficient implementations for certain types. The above example can
be rewritten with specialization as follows:
#include <iostream>
#include <cstring>
using namespace std;
//max returns the maximum of the two elements
template <class T>
T max(T a, T b) {
return a > b ? a : b ;
}
// Specialization of max for char*
template <>
char* max(char* a, char* b) {
return strcmp(a, b) > 0 ? a : b ;
}
int main() {
cout << "max(10, 15) = " << max(10, 15) << endl ;
cout << "max('k', 's') = " << max('k', 's') << endl ;
cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ;
void f()
{
size++ ; //error change of template argument value
}
};
int main() {
Stack<double,10> si ;
return 0 ;
}
6. A template-parameter that could be interpreted as either a parameter-
declaration or a type-parameter, is taken as a type-parameter. For
example,
class T {};
int i;
template <class T, T i>
void f(T t) {
T t1 = i; //template arguments T and i
::T t2 = ::i; //globals T and i
}
int main() {
f('s');
return 0 ;
}
Self Assessment Questions
8. C++ allows you to specify a default template parameter. (True/False)
9. __________________________ cannot be specified in a declaration
or a definition of a specialization.
public:
static T s;
};
int main() {
X<int> xi ;
X<char*> xc ;
}
Here X<int> has a static data member s of type int and X<char*> has a
static data member s of type char*.
3. Static members are defined as follows:
#include <iostream>
using namespace std;
template <class T>
class X {
public:
static T s;
};
template <class T> T X<T>::s = 0 ;
template <> int X<int>::s = 3 ;
template <> char* X<char*>::s = "Hello" ;
int main() {
X<int> xi ;
cout << "xi.s = " << xi.s << endl ;
X<char*> xc ;
cout << "xc.s = " << xc.s << endl ;
return 0 ;
}
Program Output:
xi.s = 10
xc.s = Hello
4. Each instantiation of a function template has its own copy of the static
variable. For example,
#include <iostream>
using namespace std;
template <class T>
void f(T t) {
static T s = 0;
s = t;
cout << "s = " << s << endl;
}
int main() {
f(10);
f("Hello");
return 0;
}
Program Output:
s = 10
s = Hello
Here f<int>(int) has a static variable s of type int, and f<char*>(char*)
has a static variable s of type char*.
The table 12.1 lists the results of declaring different kinds of friends of a
class.
Table 12.1: Different kinds of friends of a class
12.11 Summary
Templates are a fairly new addition to the C++ language, and were only
recently standardized on. They are also one of the more useful features
of C++. They allow you to create classes that are more dynamic in
terms of the types of data they can handle.
A class template is a class that is implemented with one or more type
parameters left open. The class template definition is similar to an
ordinary class definition except the prefix template<class T> and the
use of type T.
This is a process of creating a specific class from a class template and
it is called as instantiation.
It is possible to use more than one generic data type in a class template
In C++ we can create functions that use variable types. These function
templates serve as an outline or pattern for a group of functions that
differ in the types of parameters they use.
Function templates are implemented like regular functions, except they
are prefixed with the keyword template.
Multiple parameters are supported by function templates.
Like ordinary functions it is possible to overload function templates.
When the compiler generates a class, function or static data members
from a template, it is referred to as template instantiation.
In some cases it is possible to override the template-generated code by
providing special definitions for specific types. This is called template
specialization.
Each template class or function generated from a template has its own
copies of any static variables or members.
With class templates, friendship can be established between a class
template and a global function, a member function of another class or
even an entire class.
Compiling templates when required forces a restriction for multi-file
projects: the implementation (definition) of a template class or function
must be in the same file as its declaration
12.13 Answers
Self Assessment Question
1. Templates
2. template<class T>
3. Function templates
4. True
5. Generated class
6. False
7. Template specialization
8. True
9. Default arguments
10. True
11. True
12. Class templates
Terminal Questions
1. It is a simple process to create a generic class using a template with
anonymous type. The general format of class template is as follows:
class classname
{
//class member specification with anonymous type T wherever
appropriate.
………….
};
For more details refer section 12.2.1
References:
Object Oriented Programming with C++ - Sixth Edition, by
E Balagurusamy. Tata McGraw-Hill Education.
Object Oriented Programming In C++, 4/E by Robert Lafore. Pearson
Education India.
C++ Templates: The Complete Guide, By David Vandevoorde, Nicolai
M. Josuttis. Addison Wesley Professional.
C++ for Programmers, By Paul Deitel, Harvey M. Deitel. Pearson
Education.