Templates in C++
Templates allow writing generic code — code that works with any data type without needing to be rewritten for each type. Instead of writing separate add(int, int), add(float, float), and add(double, double) functions, one template handles all of them.
Why Templates?
Without templates, functions need to be overloaded for each data type — a lot of repetition. Templates solve this by letting the data type become a parameter itself:
// Without template — repetitive
int add(int a, int b) { return a + b; }
double add(double a, double b){ return a + b; }
// With template — one function for all types
template <typename T>
T add(T a, T b) { return a + b; }
Function Templates
#include <iostream>
using namespace std;
template <typename T>
T getMax(T a, T b) {
return (a > b) ? a : b;
}
int main() {
cout << getMax(3, 7) << endl; // int
cout << getMax(4.5, 2.1) << endl; // double
cout << getMax('z', 'a') << endl; // char
return 0;
}
Output:
7
4.5
zTemplate with Multiple Type Parameters
template <typename T1, typename T2>
void display(T1 a, T2 b) {
cout << a << " and " << b << endl;
}
int main() {
display(10, 3.14);
display("Hello", 100);
return 0;
}
Output:
10 and 3.14
Hello and 100Class Templates
Templates can also be applied to entire classes — allowing the class to work with different data types:
#include <iostream>
using namespace std;
template <typename T>
class Stack {
private:
T data[100];
int top;
public:
Stack() : top(-1) {}
void push(T value) {
data[++top] = value;
}
T pop() {
return data[top--];
}
bool isEmpty() {
return top == -1;
}
};
int main() {
Stack<int> intStack;
intStack.push(10);
intStack.push(20);
cout << intStack.pop() << endl; // 20
cout << intStack.pop() << endl; // 10
Stack<string> strStack;
strStack.push("Hello");
strStack.push("World");
cout << strStack.pop() << endl; // World
return 0;
}
Output:
20
10
WorldTemplate Specialization
Sometimes a template needs special behavior for a specific type. Template specialization provides a custom implementation for that type:
template <typename T>
void print(T x) {
cout << "Value: " << x << endl;
}
// Specialization for char*
template <>
void print<char*>(char* x) {
cout << "String: " << x << endl;
}
int main() {
print(42);
print(3.14);
print((char*)"Hello");
return 0;
}
Output:
Value: 42
Value: 3.14
String: HelloDefault Template Arguments
template <typename T = int>
class Box {
public:
T value;
Box(T v) : value(v) {}
void show() { cout << value << endl; }
};
int main() {
Box<> b1(100); // uses default: int
Box<double> b2(3.14); // explicit type
b1.show();
b2.show();
return 0;
}
Output:
100
3.14Templates vs Function Overloading
| Feature | Function Overloading | Templates |
|---|---|---|
| Code repetition | Separate function for each type | One template for all types |
| Flexibility | Limited to declared overloads | Works with any type automatically |
| Custom behavior per type | Easy — each function is separate | Requires specialization |
Key Takeaways
- Templates allow writing generic, type-independent code.
- Function templates define functions that work with any data type.
- Class templates define classes that can operate on any data type.
- Template specialization provides custom behavior for specific types.
- The STL (Standard Template Library) is entirely built on templates.
