Templates In C++ With Examples

Learn The Various Aspects Of Templates In C++.

Templates are one of the most powerful features in C++. Templates provide us the code that is independent of the data type.

In other words, using templates, we can write a generic code that works on any data type. We just need to pass the data type as a parameter. This parameter which passes the data type is also called a type name.

In this tutorial, we will explore all about templates and its various aspects in detail.

=> Click Here For The Absolute C++ Training Series.

Templates In C++

What Are Templates?

As mentioned above, templates are generic i.e. independent of the data type. Templates are used mainly to ensure code reusability and flexibility of the programs. We can just create a simple function or a class that takes data type as a parameter and implement the code that works for any data type.

For Example, if we want a sorting algorithm to work for all numeric data types as well as character strings, then we will just write a function that takes data type as an argument and implement the sorting technique.

Then depending on the data type (type name) that is passed to sorting algorithm, we can have the data sorted irrespective of the data type. This way we need not write ten algorithms for ten data types.

Thus templates can be used in applications wherein we require the code to be usable for more than one data types. Templates are also used in applications where code reusability is of prime importance.

How To Use Templates/Implementation?

Templates can be implemented in two ways:

  • As a function template
  • As a class template

Function Template

Function Template is just like a normal function, but the only difference is while normal function can work only on one data type and a function template code can work on multiple data types.

While we can actually overload a normal function to work on various data types, function templates are always more useful as we have to write the only program and it can work on all data types.

Next, we will see the implementation of function templates.

The general syntax of the function template is:

template<class T>
 T function_name(T args){

 ……

 //function body
 }

Here, T is the template argument that accepts different data types and class is a keyword. Instead of the keyword class, we can also write ‘typename’.

When a particular data type is passed to function_name, a copy of this function is made by the compiler with this data type as an argument and function are executed.

Let us see an example to better understand function templates.

#include <iostream>
using namespace std;

template <typename T>
void func_swap(T &arg1, T &arg2)
{
  T temp;
  temp = arg1;
  arg1 = arg2;
  arg2 = temp;
}

int main()
{
  int num1 = 10, num2 = 20;
  double d1 = 100.53, d2 = 435.54;
  char ch1 = 'A', ch2 = 'Z';
  
  cout << "Original data\n";
  cout << "num1 = " << num1 << "\tnum2 = " << num2<<endl;
  cout << "d1 = " << d1 << "\td2 = " << d2<<endl;
  cout << "ch1 = " << ch1 << "\t\tch2 = " << ch2<<endl;
  
  func_swap(num1, num2);
  func_swap(d1, d2);
  func_swap(ch1, ch2);
  
  cout << "\n\nData after swapping\n";
  cout << "num1 = " << num1 << "\tnum2 = " << num2<<endl;
  cout << "d1 = " << d1 << "\td2 = " << d2<<endl;
  cout << "ch1 = " << ch1 << "\t\tch2 = " << ch2<<endl;
  
  return 0;
}

Output:

Original data
num1 = 10 num2 = 20
d1 = 100.53 d2 = 435.54
ch1 = A ch2 = Z

Data after swapping
num1 = 20 num2 = 10
d1 = 435.54 d2 = 100.53
ch1 = Z ch2 = A

In the above program, we have defined a function template “func_swap” that swaps two values. The function takes two reference arguments of type T. It then swaps the values. As the arguments are references, whatever changes we do to arguments in the function will be reflected in the caller function.

In the main function, we define data of type int, double and char. We call function func_swap with each type of data. Then we display the swapped data for each data type.

Thus this shows that we need not write three functions for three data types. It suffices to write only one function and makes it a template function so that it is independent of the data type.

Class Templates

Like in function templates, we might have a requirement to have a class that is similar to all other aspects but only different data types.

In this situation, we can have different classes for different data types or different implementation for different data types in the same class. But doing this will make our code bulky.

The best solution for this is to use a template class. Template class also behaves similar to function templates. We need to pass data type as a parameter to the class while creating objects or calling member functions.

The general syntax for the class template is:

 template <class T>
 class className{

 …..

 public:
                             T memVar;
                             T memFunction(T args);
 };

In the above definition, T acts as a placeholder for the data type. The public members’ memVar and memFunction also use T as a placeholder for data types.

Once a template class is defined as above, we can create class objects as follows:

className<int> classObejct1;
className<float> classObject2;
className<char> classObject3;

Let us implement a code example to demonstrate Class Templates:

#include <iostream>
using namespace std;

template <class T>
class myclass {
  T a, b;
 public:
  myclass (T first, T second)
     {a=first; b=second;}
  T getMaxval ();
};
template <class T>
T myclass<T>::getMaxval ()
{
  return (a>b? a : b);
}
int main () {
  myclass <int> myobject (100, 75);
  cout<<"Maximum of 100 and 75 = "<<myobject.getMaxval()<<endl;
   
  myclass<char> mychobject('A','a');
  cout<<"Maximum of 'A' and 'a' = "<<mychobject.getMaxval()<<endl;
 
  return 0;
}

Output:

Maximum of 100 and 75 = 100
Maximum of ‘A' and ‘a' = a

The above program implements an example of a class template. We have the template class myclass. Inside this, we have a constructor that will initialize the two members a and b of the class. There is another member function getMaxval which is also a function template that returns a maximum of a and b.

In the main function, we construct two objects, myobject of type integer and mychobject of type character. Then we call the getMaxval function on each of these objects to determine maximum value.

Note that apart from template type parameters (parameters of type T), template functions can also have ordinary parameters like normal functions and also default parameter values.

typename Vs. class keyword

While declaring template class or function, we use one of the two keywords class or typename. These two words are semantically equivalent and can be used interchangeably.

But in some cases, we cannot use these words as equivalent. For Example, when we are using dependent datatypes in templates like “typedef”, we use typename instead of class.

Also, the class keyword must be used when we have to explicitly instantiate a template.

Template Instantiation And Specialization

The templates are written in a generic way, which means that it’s a general implementation irrespective of the data type. As per the data type provided, we need to generate a concrete class for each data type.

For Example, if we have a template sort algorithm, we may generate a concrete class for sort<int>, another class for sort<float>, etc. This is called instantiation of the template.

We substitute the template arguments (actual data types) for the template parameters in the definition of the template class.

For Example,

template <class T>
class sort {};

When we pass <int> data type, the compiler substitutes the data type <int> for ‘T’ so that the sorting algorithm becomes sort<int>.

Every time when we use template class or function, there is a need for an instance when we pass a particular data type. If this instance is not already present, the compiler creates one with the particular data type. This is the implicit instantiation.

One drawback of implicit instantiation is that the compiler generates instance class only for the arguments that are used currently. This means if we want to generate a library of instances ahead of the usage of these instances, we need to go for explicit instantiation.

An example of Template declaration is given below:

template class Array(T)

Can be explicitly instantiated as:

template class Array<char>

When a class is instantiated, all its members are also instantiated.

Template Specialization

While programming using templates, we might be faced with a situation such that we might require a special implementation for a particular data type. When such a situation occurs, we go for template specialization.

In template specialization, we implement a special behavior for a particular data type apart from the original template definition for the other data types.

For Example, consider we have a template class ‘myIncrement’ which has a constructor to initialize a value and a template function toIncrement that increments the value by 1.

This particular class will work perfectly for all the data types except for char. Instead of incrementing the value for char, why not give it a special behavior and convert the character to uppercase instead?

In order to do this, we can go for template specialization for the char data type.

This implementation is shown in the below code Example.

#include <iostream>
using namespace std;

// class template:
template <class T>
class myIncrement {
  T value;
  public:
  myIncrement (T arg) {value=arg;}
  T toIncrement () {return ++value;}
};
// class template specialization:
template <>
class myIncrement <char> {
   char value;
  public:
   myIncrement (char arg) {value=arg;}
   char uppercase ()
  {
    if ((value>='a')&&(value<='z'))
    value+='A'-'a';
    return value;
  }
};
int main () {
  myIncrement<int> myint (7);
  myIncrement<char> mychar ('s');
  myIncrement<double> mydouble(11.0);
 
  cout<<"Incremented int value: "<< myint.toIncrement()<< endl;
  cout<<"Uppercase value: "<<mychar.uppercase()<< endl;
  cout<<"Incremented double value: "<<mydouble.toIncrement()<< endl;
  return 0;
}

Output:

Incremented int value: 8
Uppercase value: S
Incremented double value: 12

template_specialization

In the above program that demonstrates template specialization, see the way in which we have declared a specialized template for char type. We first declare the original class and then we “specialize” it for char type. To begin specialization we use empty template declaration “template<>”.

Then after the class name, we include the data type <char>. After these two changes, the class is written for the char type.

In the main function, note that there is no difference between instantiation of char type and other types. The only difference is that we redefine the specialized class.

Note that we must define all the members of the specialized class even though they are exactly the same in the generic/original template class. This is because we do not have inheritance feature for members from the generic template to the specialized template.

C++ Variadic Templates

So far we have seen function templates that take a fixed number of arguments. There are also templates that take a variable number of arguments. These function templates are called variadic templates. Variadic templates are one of the newest features of C++11.

Variadic templates take a variable number of arguments that are type-safe and the arguments are resolved at compile-time.

Let us take a complete programming Example to understand this.

#include <iostream>
#include <string>
using namespace std;
template<typename T>
T summation(T val) {
  return val;
}
template<typename T, typename... Args>
T summation(T first, Args... args) {
  return first + summation(args...);
}
int main()
{
  long sum = summation(1, 2, 3, 8, 7);
  cout<<"Sum of long numbers = "<<sum<<endl;
  string s1 = "H", s2 = "e", s3 = "ll", s4 = "o";
  string s_concat = summation(s1, s2, s3, s4);
  cout<<"Sum of strings = "<<s_concat;
}

Output:

Sum of long numbers = 21
Sum of strings = Hello

The screenshot for the same is given below.

variadic_template

The above example demonstrates variadic function, “summation”. As shown above, we first need a base function that implements the base case. Then we implement the variadic function on the top of this function.

In the variable function summation, “typename…args” is called template parameter pack whereas “Args…args” is called function parameter pack.

After writing a function template that implements the base case, we write a variadic function that implements the general case. The variadic function is written similar to the recursion as shown for summation (args…). The first argument is separated from the function parameter pack into type T (first).

With every call to summation, the parameter list gets narrower by one argument and eventually the base condition is reached. The output shows the summation for long integers and characters.

Conclusion

With this, we conclude this tutorial on templates in C++. Templates help us to make our programs generic i.e. independent of type.

Generic programs always stand on top of the other programs as we need not write separate programs for each data type. Thus developing generic type-safe programs can be an important step towards efficient programming.

=> Check The In-Depth C++ Training Tutorials Here.