Templates are the foundation of generic programming, which is writing code in a way that is independent of any particular type.
Templates are blueprints or formulas that create generic classes or functions. Library containers, such as iterators and algorithms, are examples of generic programming that use the concept of templates.
Each container has a single definition, such as vector , and we can define many different types of vectors, such as vector<int> or vector<string> .
You can use templates to define functions and classes, let's see how to use them.
function template
The general form of a template function definition is as follows:
template <class type> ret - type func - name(parameter list) { // the body of the function }
Here, type is a placeholder name for the data type used by the function. This name can be used in function definitions.
The following is an example of a function template that returns the maximum of two numbers:
example
#include <iostream> #include <string> using namespace std; template <typename T> inline T const& Max(T const& a, T const& b) { return a < b ? b : a; } intmain() { int i = 39; int j = 20; cout << "Max(i, j): " << Max(i, j) << endl; double f1 = 13.5; double f2 = 20.7; cout << "Max(f1, f2): " << Max(f1, f2) << endl; string s1 = "Hello"; string s2 = "World"; cout << "Max(s1, s2): " << Max(s1, s2) << endl; return 0; }
When the above code is compiled and executed, it produces the following results:
Max(i, j):39Max(f1, f2):20.7Max(s1, s2):World
class template
Just as we define function templates, we can also define class templates. The general form of a generic class declaration is as follows:
template <class type> class class - name{ . . . }
Here, type is a placeholder type name that can be specified when the class is instantiated. You can define multiple generic data types using a comma-separated list.
The following example defines the class Stack<> and implements generic methods to push and pop elements from the stack:
example
#include <iostream> #include <vector> #include <cstdlib> #include <string> #include <stdexcept> using namespace std; template <class T> class Stack { private: vector<T> elems; // elements public: void push(T const&); // push the stack void pop(); // pop the stack T top() const; // return the top element of the stack bool empty() const { // Returns true if empty. return elems.empty(); } }; template <class T> void Stack<T>::push(T const& elem) { // Append a copy of the passed element elems.push_back(elem); } template <class T> void Stack<T>::pop() { if (elems.empty()) { throw out_of_range("Stack<>::pop(): empty stack"); } // delete the last element elems.pop_back(); } template <class T> T Stack<T>::top() const { if (elems.empty()) { throw out_of_range("Stack<>::top(): empty stack"); } // return a copy of the last element return elems.back(); } intmain() { try { Stack<int> intStack; // stack of type int Stack<string> stringStack; // stack of type string // Manipulate the stack of type int intStack.push(7); cout << intStack.top() << endl; // Manipulate the stack of type string stringStack.push("hello"); cout << stringStack.top() << std::endl; stringStack.pop(); stringStack.pop(); } catch (exception const& ex) { cerr << "Exception: " << ex.what() << endl; return -1; } }
When the above code is compiled and executed, it produces the following results:
7 hello Exception:Stack<>::pop(): empty stack