We have studied the concept of function overloading, in which we use the same name for various implementations of the function. The overloaded functions are distinguished utilizing the different parameter lists. In function overloading, it may be possible that multiple functions’ performance is identical except for the type of data they operate upon. The problem with function overloading is that in the program, we have to define a separate function for each data type but also if any new type is added later on, then new functions have to be written for each one.
A better solution to the above problem is to make a generic function that can work for all C++ data types. It is implemented in C++ using the concept of Templates.
Templates allow us to create a single function or a class for a group of similar functions or classes generically. The template declared for the function is called a function template, and those declared for classes are called a class template. For example – we can create a template for function cube( ) that calculates the cube of any data type, including int, float, double, etc. Templates are the fundamental tool for generic programming in C++, whose main purpose is to write reusable code. The template was originally not part of C++ and was added later.
We’ll be covering the following topics in this tutorial:
Need for Templates
To understand the need of templates, consider a program in which we overload min() function for calculating minimum of two integer values, float values and character values as shown below :
#include<iostream. h> int min(int a,int b) {return(a<b)?a:b;} float min(float a,float b) {return(a<b)?a:b;} char min(char a,char b) {return(a<b)?a:b;} int main() { int x,y; cin>>x>>y; //Input two integer values cout<<"Min of integer values is = "<<min(x,y); float p,q; cin>>p>>q; //Input two floating values cout<<"Minimum of floating values = "<<min(p,q); char c1,c2; cin>>c1>>c2; //Input two characters cout<<"Minimum of c1 and c2 (basis of ASCII value) = "<<min(c1, c2); return 0; } Output 5 10 Min. of integer values is = 5 14.5 27.5 Minimum of floating values = 14.5 a rn Minimum of cl and c2 (basis of ASCII value) = a
In the above program, we observe that the implementation of each min() function is the same and differs only in their data type. If you want to calculate the minimum of some other type, such as double, then you need to copy the code, paste it and change the data type. So, defining multiple identical functions that differ only in terms of data type increases the code’s size due to redundancy. Also, there is a maintenance problem in the program. Suppose there are some logical errors in the implementation of the algorithm used by the function. In that case, it is more likely that the same logical error exists in every version of the overloaded function, and we need to modify all the definitions.
This problem can be resolved if there is a way to write such a function only once, which could work for various data types. It can be achieved by using the concept of function templates in C++. If we use the function template in the above program, the min() function would be implemented only once to work for many different data types.
There are two types of templates in C++ Function template and class template.
Function template
Function Templates are generic functions that can handle different data types without writing separate code for each of them. Using function templates, the same code need not be repeatedly written for different data types, thus reducing manual effort in development, testing, and debugging a program. A well-defined function template will go a long way in saving time for programmers.
The syntax for a function template that takes a parameter of a single data type is as follows:
template<class T> T Function_name (T par1, T par2 ,........) { //template function body }
All function templates begin with a keyboard template which informs the compiler that we are about to define a function template. The template type parameter T enclosed in angled brackets, and parameter T must be preceded by keyword class which establishes that T is a datatype. Some compilers may use keyword type names instead of class, but both refer to any built-in type or user-defined type.
It is followed by the function definition that is the same as that of normal function definition except that in place of an explicit data type such as int, the generic data type T is used instead. The type parameter T can specify the type of the arguments to the function, return type and declare variables within the function.
From the above syntax of a function template, it is clear that templates are not implemented for a particular data type but for a data type yet to be defined, which is only known at the point of call to a function template. When you call the function template, the compiler replaces the generic type T by the data type of the argument being passed to the function.
We will modify the previous program by using the function template to evaluate the minimum of two values of any data type.
#include<iostream.h> #include<conio.h> template<class T> T min(T a,T b) { return (a<b)?a:b; } int main() { clrscr(); int x,y; cin>>x>>y; cout<<"Min of inteqer values is "<<min(x,y); float p,q; cin>>p>>q; cout<<"Minimum of floating values "<<min(p,q); char c1,c2; cin>>c1>>c2; cout<<"Minimum of c1 and c2 (basis of ASCII values)= "<<min(c1,c2); getch(); return 0; } Output : 5 10 Min. of integer values is 14.5 27.5 Minimum of floating value = 14.5 a m Minimum of c1 and c2 (basis of ASCII value) = a
Explanation: In this program, we define a function template min() that computes the minimum of two values of any data type. The statements within the function template min() are not different from those defined in the previous program. Here, the minimum of two values of type T is processed using the comparison operator and result is returned.
When the compiler encounters function template definition, it cannot compile it as compiler does not know yet what data type the function will be working with. This is true as it is impossible for the compiler to generate code without knowing the data type and only performs syntax checking.
When the compiler encounters a function call, min(x, y) in the statement
cout<<"Min. of integer values is = "<<min(x,y);
The int data type is substituted for every occurrence of T in the min() function template definition (as x and y are of int type) and internally creates a specific version of min() function for type int as follows.
int min(int a,int b) { return(a<b)?a:b; }
The process of creating a function from a template by substituting actual data types for its parameters is called instanting the function template. Each instantiated version of the function template is called template function.
Similarly, when compiler encounters the function calls min(p, q) and min(c1 ,c2) , compiler generates new versions of min() that operate on type float and char respectively and the float and char data types are substituted for T throughout the template definition.
#include<iostream.h> #include<conio.h> template<class T> void swap(T &m,T &n) { T temp; temp = m; m = n : n = temp; } int main() { clrscr(); int a,b; cin>>a>>b; swap(a,b); //calls function template for int cout<<"a = "<<a<<"\tb = "<<b; float x,y; cin>>x>>y; swap(x,y); //calls function template for float cout<<"x = "<<x<<"\ty = "<<y; char c1,c2; cin>>c1>>c2; swap(c1,c2); //calls function template for char cout<<"c1 = "<<c1<<"\t c2 = "<<c2; getch(); return 0; } Output: 3 9 a = 9 2.5 b = 3 5.75 x = 5.75 y = 2.5 a m c1 = m c2 = a
Class Templates
We have studied function templates that help us write generic functions using a single implementation that operates on different data types. Like function templates, we can create generic classes using class templates that provide the same functionality for various data types. C++ class templates are usually used in the container classes such as stacks, queues, vectors, lists, etc. Once the code is written as a class template, it can support multiple data types. Consider an example of a stack data structure in which items can be added and removed from the top in LIFO (Last in First Out) order. A stack may store items of any data type but not a mixture of data types. The code used for maintaining a stack of integers can also work for a stack of float or character or double types. Instead of creating separate stack classes for different data types, we can create a stack class template and use it to define stacks that can store different data types. The general form of creating a class template is given below:
template <class T> class class_name { // class definition };
As with the function template, the class template always begins with a keyword template followed by angular brackets < > which specify the type parameter T that the class will operate. The keyword class preceded by type parameter T indicates that T represents built-in or user-defined data type. It is followed by the class template definition in which we use the type parameter T, whose behavior is similar to that of built-in or user-defined data types used in the non-template class definition. So, type parameters can be used to declare data members, member functions, etc.
If we want to create a generic stack class, then the class template can be written as follows.
template<class T> class stack { T array [20]; int top; public : stack(); void push(T item); T pop(); void display() ; };
After the creation of the generic class, an object of the class template can be instantiated using the following form :
class_name <datatype> object_name;
Here, class_name denotes the class template’s name, and object_name is the instance of class_name. The data type refers to the actual data type, which replaces template parameter type T within the class template definition. This process of type substitution is called template instantiation.
For example, The statement to create an object of type stack for storing int values is as follows,
stack <int> s1;
This statement instantiates the stack class for object s1 for storing int values, and each occurrence of template parameter T within the class template definition is replaced with type int. The complete program that implements a class stack for different data types using a class template is shown.
#include<iostream.h> #include<conio.h> #include<process.h> const int MAX=10; template <class T> class stack { private: T array[MAX]; int top; public: stack() { top=-1; } void push(T item) { if (top==(MAX-1)) { cout<<"stack overflow"; exit(0); } else { top++; array[top]=item; } }//end of push() T pop() { if (top== -1) { cout<<"Underflow"; exit(0); } else { T elem=array[top--]; return elem; } } //end of pop() }; int main() { clrscr(); stack <int> s1;· s1.push(10);//pushing 10 int value to stack s1.push(20); cout<<"Element to be popped "<<s1.pop(); stack <float> s2; s1.push(5.5); s2.push(l0.7); cout<<"\nElement to be popped "<<s2.pop() ; getch(); return 0; }
Explanation: The above program creates a generic stack class that can store any built-in values. The statement,
stack <int> s1;
creates an object s1 of type stack that can store int values in the stack. This instantiation provides space to all the data members and member functions of object s1 by replacing each template parameter T with int.
The next statements push and pop elements into and from the stack. Then the contents of the stack are displayed. Similarly, the statement,
stack <float> s2;
creates an object s2 of type stack that can store float type values in the stack. This instantiation allocates separate space for all members of s2’s object by substituting each occurrence of template parameter T with the float. The next statements push and pop elements of float type into and from the stack whose contents are finally displayed.
In the above program, the member functions of the class template are defined inside the class. However, we can define these member functions outside the class template using the scope resolution operator in the case of member functions in the non-template class. One should always keep in mind that the expression template <class T> must precede the member function’s definition, specifying that the member function is part of the template.
The push() member function is defined outside the class template will be as shown.
template<class T> void stack<T>::push(T item) { if(top==(SIZE-1)) { cout<<"stack overflow"; exit(0); } else { top++; array[top]=item; } }