News & UpdatesProgrammingWeb programming StoreMy Projects
Links
Affiliates

C++ Tutorial – 28 – Templates

Templates provide a way to make a class or function operate with different data types without having to rewrite the code for each type.

Function templates

The example below shows a function that swaps two integer arguments.

void swap(int& a, int& b)
{
  int tmp = a;
  a = b;
  b = tmp;
}

To convert this method into a function template that can work with any type the first step is to add a template parameter declaration before the function. This declaration includes the template keyword followed by the keyword class and the name of the template parameter, both enclosed between angle brackets. The name of the template parameter may be anything, but it is common to name it with a capital T.

template<class T>

Alternatively, the keyword typename can be used instead of class. They are both equivalent in this context.

template<typename T>

The second step in creating a function template is to replace the data type that will be made generic with the template parameter.

template<class T>
void swap(T& a, T& b)
{
  T tmp = a;
  a = b;
  b = tmp;
}

Calling function templates

The function template is now complete. To use it swap can be called as if it was a regular function, but with the desired template argument specified in angle brackets before the function arguments. Behind the scenes, the compiler will instantiate a new function with this template parameter filled in, and it is this generated function that will be called from this line.

int a = 1, b = 2;
swap<int>(a,b); // calls int version of swap

Every time the function template is called with a new type, the compiler will instantiate another function using the template.

bool c = true, d = false;
swap<bool>(c,d); // calls bool version of swap

In this example, the swap function template may also be called without specifying the template parameter. This is because the compiler can automatically determine the type, because the function template’s arguments use the template type. However, if this was not the case, or if there is a need to force the compiler to select a specific instantiation of the function template, the template parameter would then need to be explicitly specified within angle brackets.

int e = 1, f = 2;
swap(e,f); // calls int version of swap

Multiple template parameters

Templates can be defined to accept more than one template parameter by adding them between the angle brackets.

template<class T, class U>
void swap(T& a, U& b)
{
  T tmp = a;
  a = b;
  b = tmp;
}

The second template parameter in the example above allows swap to be called with two arguments of different types.

int main()
{
  int a = 1;
  long b = 2;
  swap<int, long>(a,b);    
}

Class templates

Class templates allow class members to use template parameters as types. They are created in the same way as function templates.

template<class T>
class MyBox
{
 public: 
  T a, b;
};

Unlike function templates, a class template must always be instantiated with explicitly specified template parameters.

MyBox<int> box;

Another thing to remember when using class templates is that if a method is defined outside of the class template that definition must also be preceded with the template declaration.

template<class T>
class MyBox
{
 public: 
  T a, b;
  void swap();
};
 
template<class T>
void MyBox<T>::swap()
{
  T tmp = a;
  a = b;
  b = tmp;
}

Notice that the template parameter is included in the swap template function definition after the class name qualifier. This specifies that the function’s template parameter is the same as the template parameter of the class.

Non-type parameters

In addition to type parameters, templates can also have regular function-like parameters. As an example, the int template parameter below is used to decide the size of an array.

template<class T, int N>
class MyBox
{
 public: 
  T store[N];
};

When this class template is instantiated, both a type and an integer have to be included.

MyBox<int, 5> box;

Default types and values

Class template parameters can be given default values and types.

template<class T = int, int N = 5>

To use these defaults the angle brackets just need to be left empty when instantiating the class template.

MyBox<> box;

Note that default template parameters may not be used in function templates.

Class template specialization

If there is a need to define a different implementation for a template when a specific type is passed as the template parameter, a template specialization can be declared. For example, in the following class template there is a print method that outputs the value of a template variable.

#include <iostream>
 
template<class T> 
class MyBox
{
 public: 
  T a;
  void print() { std::cout << a; }
};

For example, when the template parameter is a bool the method should print out “true” or “false” instead of “1” or “0”. One way to do this would be to create a class template specialization. A reimplementation of the class template is then created where the template parameter list is empty. Instead, a bool specialization parameter is placed after the class template’s name and this data type is used instead of the template parameter throughout the implementation.

template<>
class MyBox<bool>
{
 public: 
  bool a;
  void print() { std::cout << (a ? "true" : "false"); }
};

When this class template is instantiated with a bool template type, this template specialization will be used instead of the standard one.

int main() 
{
  MyBox<bool> box = { true }; 
  box.print(); // true
}

Note that there is no inheritance of members from the standard template to the specialized template. The whole class will have to be redefined.

Function template specialization

Since there is only one function that is different between the templates in the example above, a better alternative would be to create a function template specialization. This kind of specialization looks very similar to the class template specialization, but is only applied to a single function instead of the whole class.

#include <iostream>
 
template<class T> 
class MyBox
{
 public: 
  T a;
 
  template<class T> void print() { 
    std::cout << a; 
  }
 
  template<> void print<bool>() { 
    std::cout << (a ? "true" : "false"); 
  }
};

This way only the print method has to be redefined and not the whole class.

int main() 
{
  MyBox<bool> box = { true }; 
  box.print<bool>(); // true
}

Notice that the template parameter has to be specified when the specialized function is invoked. This is not the case with the class template specialization.

Recommended additional reading:
Sams - Teach Yourself C++ in One Hour a Day