Templates in C++

What are Templates in C++?

Now we will discuss one of C++’s more powerful features, namely templates. Function templates and class templates enable programmers to specify, with a single code segment, an entire range of related(overloaded) functions called function templates specializations or an entire range of related classes called class template specializations.

We might write a single function template for an array sort function, then have C++ generate separate function-template specializations that will sort int arrays, float arrays, arrays of strings and so on.C++ generate separate class-templates specializations, such as a stack-of-int class, a stack of float class, a stack-of-string class and so on

Function templates and class templates are like stencils out of which we trace shapes; function-template specializations and class-template specializations are like the separate tracings that all have the same shape, but could, for example, be drawn in different colors.

Templates are one of C++’s most powerful capabilities for software reuse

We will discuss C++ features, such as overloading, inheritance, friends and static members.

Types of Templates in C++

1.Function Templates
2.Class Templates

1.Function Templates

Overloaded functions are normally used to perform similar operations that involve different program logic on different data types. If the program logic and operations are identical for each data type, overloading may be performed more compactly and conveniently by using the function templates. The programmer writes a single function template definition Given the argument types provided in the call to this function, C++ automatically generates separate function-template defines a whole family of solutions.

All function template definition begins with the template keyword followed by a list of formal type parameters to the function template enclosed in angle brackets(< and >). Every formal type parameter is preceded by keyword typename or keyword class.

template<class T>
or
template<typename ElementType>
or
template<class BorderType,class FillType>

The formal type parameters are a placeholder for built-in-types or user-defined types. These placeholders are used to specify the types of arguments to the function, to specify the return type of the function and to declare variables within the body of the function definition. The function definition follows and is defined as any other function, using the formal type parameters as placeholders for actual data types.

template<class T>
T maximum(T value1,T value2, T value3)
{
T max=value1;
if(value2>max)
max=value2;
if(value3>max)
max=value3;
return max;
}

This function template declares a single formal type parameter T is a placeholder for the type of the data to be tested by function maximum. When the compiler detects a maximum invocation in the program source code, the type of the data passed to the maximum is substituted for T throughout the template definition, and C++ creates a complete function for determining the maximum of three values of the specified data type. Then the newly created function is compiled. Thus, templates are a mean of code generation. One expects three int values, one expects three double values and one expects three char values. The specialization created for type int replaces each occurrence of T with int as follows:

int maximum(int value1,int value2,int value3)
{
int max=value1;
if(value2>max)
max=value2;
if(value3>max)
max=value3;
return max;
}

The name of a type parameter must be unique in the formal parameter list of a particular template definition

1.Programs of Function Templates

#include<iostream>
using std::cout;
using std::cin;
using std::endl;
template<class t>
T maximum(T value, T value2, T value3)
{
T max=value1;
if(value2>max)
max=value2;
if(value3>max)
max=value3;
return max;
}
int main()
{
int int1,int2,int3;
cout<<"input three integer values:";
cin>>int1>>int2>>int3;
cout<<"The maximum integer value is:"
     <<maximum(int1,int2,int3);
double double1,double2,double3;
cout<<"\n\nInput three double values:";
cin>>double1>>double2>>double3;    
cout<<"The maximum double value is:"
    <<maximum(double1,double2,double3);
char char1,char2,char3;
cout<<"The maximum character value is:"
   <<maximum(char1,char2,char3)
   <<endl;
return 0; 
}

OUTPUT:

Input three integer values:1 2 3
The maximum integer value is:3

Input three double values:3.3 2.2 1.1
The maximum double value is :3.3

Input three characters:A C B
the maximum character value is:C

2.Programs of Function Templates

#include<iostream>
using std::cout;
using std::endl;
template<class T>
void printArray(const T*array,const int cout)
{
for(int i=0;i<count;i++)
cout<<array[i]<<" ";
cout<<endl;
}
int main()
{
const int aCount=5;
const int bCount=7;
const int cCount=6;
int a[aCount]={1,2,3,4,5,6,7,7};
char c[cCount]="HELLO";
cout<<"Array a contains:"<<endl;
printArray(a,aCount);
cout<<"Array b cintains:"<<endl;
printArray(b,bCount);
cout<<"Array c contains:"<<endl;
printArray(c,cCount);
return 0;
}

OUTPUT:

Array a contains 1 2 3 4 5 Array b contains: 1.1 2.2 3.3 4.4 5.5 6.6 7.7 Array c contains: HELLO

Overloading Function Templates

Function templates and overloading are intimately related. The related function-template specializations generated from a function template all have the same name, so the compiler uses overloading resolution to invoke the proper function.

A function template may be overloaded in several ways. We can provide other function templates that specify the same function name but different function parameters. For example, function template printArray could be overloaded with another printArray function template with additional parameters lowSubscript and highSubscript to specify the portion of the array to output. A function template also can be overloaded by providing non-template version that specifically prints an array of character strings in neat, tabular format

If a template is invoked with a user-defined type, and if that template uses operators(e.g. ==,+,<=) with objects of that class type, then those operators must be overloaded for the user-defined type.Forgetting to overload such operators causes errors.

The compiler performs a matching process to determine what function to call when a function is invoked. First, the compiler tries to find and use a precise match in which the function names and argument types match those of the function call. If this fails, the compiler determines whether a function template is available that can be used to generate a function-template specialization with a precise match of the function name and argument types. If such a function template is found, the compiler generates and uses the appropriate function-template specialization.

2.Class Templates

It is possible to understand the concept of a “stack”(a data structure into which we insert items at the top and retrieve those items in last-in-first-out order) independent of the type of the items being placed in the stack. However, to instantiate a stack, a data type must be specified. This creates a wonderful opportunity for software reusability. We need the means for describing the notion of a stack generically and instantiating classes that are type-specific versions of this generic class.C++ provides this capability through class templates. and technique is called generic programming

Class templates encourage software reusability by enabling type-specific versions of generic classes to be instantiated

Class templates are called parameterized types because they require one or more type parameters to specify how to customize a “generic class” template to form a class-template specialization. The programmer requires One Stack class template, for example, could thus become the basis for creating many Stack classes(such as “Stack of double”, “Stack of int”, “Stack of char”, “Stack of Employee”etc.) used in a program. The Stack class-template definition can be written as

template<class T> //class-template definition with type parameter
#include<iostream>
using std::cout;
using std::cin;
using std::endl;
#include "tstack1.h"  //Stack class template definition
int main()
{
Stack<double>doubleStack(5);
double doubleValue=1.1;
cout<<"Pushing elements onto doubleStack\n";
while(doubleStack.push(doubleValue))
{
cout<<doubleValue<<' ';
doubleValue+=1.1;
}
cout<<"\nStack is ful.Cannot push"<<doubleValue
    <<"\n\nPopping elements from doubleStack\n";
while(doubleStack.pop(doubleValue))
cout<<doubleValue<<' ';
cout<<"\n Stack is empty.Cannot pop\n";
Stack<int> intStack;
int intValue=1;
cout<<"\nPushing elements onto intStack\n";
while(intStack.push(intValue))
{
cout<<intValue<<' ';
++intValue;
}
cout<<"\nStack is full.Cannot push"<<intValue
    <<"\n\nPopping elements from intStack\n";
while(intStack.pop(intValue))
cout<<intValue<<' ';
cout<<"\nStack is empty.Cannot pop\n";
return 0;
}

OUTPUT:

Pushing elements onto doubleStack
1.1 2.2 3.3 4.4 5.5
Stack is full.Cannot push 6.6

Popping elements from doubleStack
5.5 4.4 3.3 2.2 1.1
Stack is empty.Cannot pop 

Class Templates and Nontype Parameter

It is also possible to use nontype parameters, which can have a default argument and are treated as consts.For example, the template header could be modified to take an int elements parameter as follows:

 template<class T,int elements>   //non-type parameter

Then, a declaration such as

Stack <double,100>mostRecentSalesFigures;

could be used to instantiate(at compile time) a 100-element Stack clas-template specialization of double values named mostRecentSalesFigures; this class-template specialization would be of type Stack<double, 100>. The class header then might contain a private data member with an array declaration such as

  T stackHolder[elements]; //array to hold stack contents

In addition, a type parameter can specify a default type. For example,

template<class T=string>

might specify that a Stack contains string objects by default

Whenever possible, specify the size of a container class(such as an array class or stack class) at compiler time(possibly through a nontype template size parameter). This eliminates the execution-time overhead of using new to create the space dynamically.

Whenever possible, specify the size of a container class(such as an array class or a stack class) at compile time (possibly through a nontype template size parameter).This eliminates the execution-time overhead of using new to create the space dynamically

Templates and Inheritance

Templates and inheritance relate in several ways:

  • A class template can be derived from a class-template specialization
  • A class template can be derived from a non-template class
  • A class-template specialization can be derived from a class-template specialization
  • A non-template class can be derived from a class-template specialization

Templates and Friends

We have seen that functions and entire classes can be declared as friends of non-template classes. With class templates, friendship can be established between a class template and a global function, a member function of another class(possibly a class-template specialization), or even an entire class(possibly a class-template specialization). The notations required to establish this friendship relationship can be cumbersome.

Inside a class template for class X that has been declared with

template<class T> class X

a friendship declaration of the form

friend void f1();

makes function f1 a friend of every class-template specialization instantiated from the preceding class template.

Inside a class template for class X that has been declared with

template<class T>class X

a friendship declaration of the form

friend void f2(B<T>&);

for particular type T such as float makes function f2(X<float>&) a friend of only class-template specialization X<float>

Inside a class-template, you can declare that a member function of another class is a friend of any class-template specialization generated from the class template. Name the member function of the other class, using the class name and the binary scope-resolution operator. For example, inside a class template for class X that has been declared with

template<class T> class X
//a friendship declaration of the form
friend void A ::f4();
makes member function f4 of class A a friend of every class-template specialization instantiated from the preceding class template
     Inside a class template for class X that has been declared with
   template<class T>class X
a friendship declaration of the form
   friend void C<T>::f5(X<T>&);
for a particular type T such ads float makes member function
   C<float>::f5(X<float>&)
a friend function of only class-template specialization X<float>
   Inside a class template for class X that has been declared with
   template<class T> class X
 a second class Y can be declared with
   friend class Y;
making every member function of class Y a friend of every class-template specialization produced from the class template X
  Inside a class template for class X that has been declared with
   template<class T> class X
a second class Z can be declared with
friend class Z<T>; 

Then, when a class-template specialization is instantiated with a particular type for T(such as float), all members of class Z<float>become friends of class-template specialization B<float>.

Templates and static Member

Remember that, with a non-template class, one copy of a static data member is shared among all objects of the class and the static data member must be initialized at file scope.

Each class-template specialization instantiated from a class template has its own copy each static data member of the class template; all objects of that specialization share that one static data member. In addition, as with static data members of non-template classes, static data members of class-template specialization must be initialized at file scope. Each class-template specialization gets its own copy of the class template’s static member functions.

Translate »