Templates
Intro To Templates
Templates allow us to define one function that applies to all types of variables. Templates are an example of "Algorithm Abstraction", which is the expression of algorithms in a general way so we can ignore details and concentrate on the substantive parts of the algorithm.
Syntax:
template<class T>
This tells the compiler that the definition/declaration that follows is a template and that 'T' is a type parameter. In the following definition/declaration,
T
can be replaced by any type, whether the type is a class or not. The compiler produces a separate definition only for the types which use the template, as required.
template<class T>
void swapValues(T& var1, T& var2) {
T temp;
temp = var1;
var1 = var2;
var2 = temp;
}
int int1 = 1, int2 = 2;
swapValues(int1, int2);
char sym1 = 'A', sym2 = 'B';
swapValues(sym1, sym2);
Note that we call the function just like any other function
Multiple Parameters
Templates can also be defined with multiple parameters, however, the following definition/declaration cannot have any unused template parameters. i.e.
template <class T1, class T2>
Class Templates
Class templates can be used to generalize a class. Defining class templates is the same as for function templates. Once the class template is defined, we can declare object of the class. The declaration must specify what type to be filled in for T. e.g.
Pair score; Pair seats;
//Class for a pair of values of type T:
template<class T>
class Pair {
public:
Pair();
Pair(T firstValue, T secondValue);
void setFirst(T newValue);
void setSecond(T newValue);
T getFirst() const;
T getSecond() const;
private:
T first;
T second;
};
Member Functions For Class Templates
Member functions that are a part of a class template is defined in the same way as member functions for ordinary classes. The only difference is that the member functions are also templates. The class name before the scope resolution operator has to have the template parameter. However, the constructor and destructor names (after scope resolution operator) do
not have the template parameter.
template<class T>
Pair<T>::Pair(T firstValue, T secondValue) {
first = firstValue;
second = secondValue;
}
Class Templates As Parameters
Class templates may be used as the type for a function parameter.
int addUp(const Pair<int>& thePair);
They can also be used within a function template.
template<class T>
T addUp(const Pair<T>& thePair);
Type Definitions
We can also define a new class type name that has the same meaning as a specialized class template name, using
typedef
(more on typedefs
here). i.e.
typedef Class_Name<T> New_Type_Name;
typedef Pair<int> PairOfInt;
Friend Functions
When used with template classes, you must include a type parameter where appropriate.
Inheritance
When defining a derived template class, begin with a standard template class and derive the other template class from it.
// Base Class
template<class T>
class Base {
public:
Base();
virtual ~Base();
private:
T *a;
};
template<class T>
Base<T>::Base() {
a = new T[5];
}
template<class T>
Base<T>::~Base() {
delete[] a;
}
// Derived Class
template<class T>
class Derived : public Base<T> {
public:
Derived();
virtual ~Derived();
private:
T *b;
}
template<class T>
Derived<T>::Derived() : Base<T>() {
b = new T[5];
}
template<class T>
Derived<T>::~Derived() {
delete[] b;
}
Maps
Maps are a templated class that are containers of key-value pairs. The key values are used to sort and uniquely identify the elements while the mapped values store the content associated with the key. The elements are sorted by its key using the operator
<
. To use user-defined classes as keys, the class must be:
- Copyable
- Assignable
- Comparable (must implement operator
<
)
#include <map>
using namespace std;
// main
map <string, int> m;
m["abc"] = 1;
m["def"] = 4;
cout << m["abc"] << endl; // 1
cout << m["ghi"] << endl; // if key is not defined, it will call the default constructor of value type and insert it in that key (prints 0)
m.erase("abc");
if(m.count("def")) {} // 0 if not found, 1 if found
for (auto &p : m)
cout << p.first << p.second << endl;
// p.first gets key
// p.second gets value