Module 11: Templates (Generic Programming)
Chapter 11 • Advanced
Templates (Generic Programming)
Templates are one of C++'s most powerful features, enabling generic programming - writing code that works with any data type. They're the foundation of the STL and modern C++.
What are Templates?
Templates allow you to write code that works with different data types without rewriting it for each type. Think of templates as "blueprints" for generating code.
Benefits:
- Code Reusability: Write once, use with any type
- Type Safety: Compile-time type checking
- Performance: No runtime overhead (code generated at compile time)
- Flexibility: Works with user-defined types
Function Templates
Function templates allow functions to work with different types.
Basic Function Template
Syntax:
template <typename T>
return_type function_name(T parameter) {
// function body
}
Example:
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
int main() {
cout << maximum(10, 20) << endl; // int
cout << maximum(3.5, 2.1) << endl; // double
cout << maximum('a', 'z') << endl; // char
return 0;
}
Multiple Template Parameters
template <typename T, typename U>
void printPair(T first, U second) {
cout << first << ", " << second << endl;
}
int main() {
printPair(10, "Hello"); // int, string
printPair(3.14, 'A'); // double, char
return 0;
}
Template Type Deduction
Compiler automatically deduces types:
template <typename T>
void display(T value) {
cout << value << endl;
}
display(10); // T = int
display(3.14); // T = double
display("Hello"); // T = const char*
Explicit Template Arguments
Specify types explicitly:
template <typename T>
T add(T a, T b) {
return a + b;
}
int result = add<int>(5, 3); // Explicit
double result2 = add<double>(5.5, 3.2);
Class Templates
Class templates allow classes to work with different types.
Basic Class Template
Syntax:
template <typename T>
class ClassName {
// class members
};
Example:
template <typename T>
class Stack {
private:
vector<T> elements;
public:
void push(const T& element) {
elements.push_back(element);
}
void pop() {
if (!elements.empty()) {
elements.pop_back();
}
}
T top() const {
return elements.back();
}
bool empty() const {
return elements.empty();
}
};
int main() {
Stack<int> intStack;
intStack.push(10);
intStack.push(20);
Stack<string> stringStack;
stringStack.push("Hello");
stringStack.push("World");
return 0;
}
Template Member Functions
Member functions defined outside class:
template <typename T>
class Vector {
private:
T x, y;
public:
Vector(T x, T y);
T getX() const;
T getY() const;
};
// Definition outside class
template <typename T>
Vector<T>::Vector(T x, T y) : x(x), y(y) {}
template <typename T>
T Vector<T>::getX() const {
return x;
}
Template Specialization
Provide specific implementation for particular types.
Function Template Specialization
template <typename T>
void print(T value) {
cout << "Generic: " << value << endl;
}
// Specialization for strings
template <>
void print<string>(string value) {
cout << "String: " << value << endl;
}
int main() {
print(10); // Generic
print(3.14); // Generic
print(string("Hi")); // String specialization
return 0;
}
Class Template Specialization
template <typename T>
class Container {
public:
void display() {
cout << "Generic container" << endl;
}
};
// Specialization for int
template <>
class Container<int> {
public:
void display() {
cout << "Integer container" << endl;
}
};
Template Parameters
Non-Type Template Parameters
Templates can take values, not just types:
template <typename T, int N>
class Array {
private:
T data[N];
public:
T& operator[](int index) {
return data[index];
}
int size() const {
return N;
}
};
int main() {
Array<int, 5> arr; // Array of 5 integers
Array<double, 10> arr2; // Array of 10 doubles
return 0;
}
Default Template Parameters
template <typename T = int, int N = 10>
class Buffer {
T data[N];
};
int main() {
Buffer<> buffer1; // Uses defaults: int, 10
Buffer<double> buffer2; // double, 10
Buffer<int, 20> buffer3; // int, 20
return 0;
}
Template Constraints (C++20)
Concepts (C++20) allow constraining template parameters:
template <typename T>
concept Addable = requires(T a, T b) {
a + b;
};
template <Addable T>
T add(T a, T b) {
return a + b;
}
Variadic Templates (C++11)
Templates that accept variable number of arguments:
template <typename... Args>
void print(Args... args) {
((cout << args << " "), ...); // C++17 fold expression
}
int main() {
print(1, 2.5, "Hello", 'A'); // Works with any number of args
return 0;
}
Common Template Patterns
Pattern 1: Generic Swap
template <typename T>
void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
Pattern 2: Generic Find
template <typename Iterator, typename T>
Iterator find(Iterator first, Iterator last, const T& value) {
for (Iterator it = first; it != last; ++it) {
if (*it == value) {
return it;
}
}
return last;
}
Pattern 3: Generic Container
template <typename T>
class Queue {
private:
vector<T> elements;
public:
void enqueue(const T& item) {
elements.push_back(item);
}
void dequeue() {
if (!elements.empty()) {
elements.erase(elements.begin());
}
}
T front() const {
return elements.front();
}
};
Template Metaprogramming (Advanced)
Templates can be used for compile-time computation:
template <int N>
struct Factorial {
static const int value = N * Factorial<N - 1>::value;
};
template <>
struct Factorial<0> {
static const int value = 1;
};
int main() {
cout << Factorial<5>::value << endl; // Computed at compile time!
return 0;
}
Best Practices
- ✅ Use templates for code that works with multiple types
- ✅ Prefer typename over class in template declarations
- ✅ Use const references for template parameters when possible
- ✅ Document template requirements (what operations T must support)
- ✅ Use concepts (C++20) for better error messages
- ✅ Avoid unnecessary template specialization
- ✅ Keep templates in header files (usually)
- ✅ Use SFINAE (Substitution Failure Is Not An Error) carefully
Common Mistakes
- ❌ Forgetting to include template definition in header
- ❌ Template instantiation errors (unclear error messages)
- ❌ Circular template dependencies
- ❌ Not understanding template instantiation
- ❌ Overusing templates when not needed
- ❌ Template specialization conflicts
Next Module
In Module 12, we'll learn about Smart Pointers - modern C++ memory management that eliminates many common pointer errors!
Hands-on Examples
Function Templates
#include <iostream>
#include <string>
using namespace std;
// Function template for maximum
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
// Function template for swap
template <typename T>
void swapValues(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
// Function template with multiple types
template <typename T, typename U>
void printPair(T first, U second) {
cout << "Pair: " << first << ", " << second << endl;
}
int main() {
// Works with integers
cout << "Max of 10 and 20: " << maximum(10, 20) << endl;
// Works with doubles
cout << "Max of 3.5 and 2.1: " << maximum(3.5, 2.1) << endl;
// Works with characters
cout << "Max of 'a' and 'z': " << maximum('a', 'z') << endl;
// Works with strings
cout << "Max of 'apple' and 'banana': " << maximum(string("apple"), string("banana")) << endl;
// Swap function
int x = 10, y = 20;
cout << "\nBefore swap: x = " << x << ", y = " << y << endl;
swapValues(x, y);
cout << "After swap: x = " << x << ", y = " << y << endl;
// Multiple types
printPair(10, "Hello");
printPair(3.14, 'A');
return 0;
}Function templates allow you to write one function that works with multiple types. The compiler generates specific versions for each type used. Use typename or class keyword. Templates provide type safety and code reuse without performance overhead.
Practice with Programs
Reinforce your learning with hands-on practice programs
Related Program Topics
Recommended Programs
Hello World
BeginnerThe classic first program that prints "Hello World" to the console
Display Your Name
BeginnerProgram to display your name on the screen
User Input
BeginnerProgram to take input from user and display it
Array Max & Min
BeginnerProgram to find maximum and minimum element in an array
Array Average
BeginnerProgram to calculate average of array elements