Object Oriented ProgrammingUnit 810 min read
Templates & Generic Programming: Reusable Code Design
Unit 8 of Object Oriented Programming covers templates (function/class), generic programming, and type-independent code in C++. Learn how to write flexible, reusable components (e.g., containers, algorithms) that work with any data type without code duplication, with real-world examples from Nepalese apps and traced ex
TAKEAWAYS:
- Templates let you write one function/class that works for multiple data types (e.g.,
swap<T>,vector<T>). - Function templates are declared with
template <typename T>and instantiated at compile-time. - Class templates create families of classes (e.g.,
Stack<int>,Stack<string>) with identical logic but different types. - Generic programming avoids code duplication by parameterizing types (e.g., STL containers like
list<T>,map<K,V>). - Type deduction (
autoanddecltype) simplifies template usage in modern C++. - Common pitfalls: forgetting angle brackets
<>, mixing templates with pointers, or overusing them for non-generic code.
1. Why Templates? The Problem They Solve
1.1 The "Copy-Paste" Nightmare
Before templates, if you wrote a swap function for int, you had to rewrite it for double, string, etc.:
void swapInt(int &a, int &b) { int temp = a; a = b; b = temp; }
void swapDouble(double &a, double &b) { double temp = a; a = b; b = temp; }
Solution: Templates let you write one swap that works for any type:
template <typename T>
void swap(T &a, T &b) { T temp = a; a = b; b = temp; }
Visual: How swap<T> works for int vs. string:
flowchart TD
A["swap<int>(x, y)"] -->|"Compile-time"| B["T = int\nT temp = x;\nx = y;\ny = temp;"]
C["swap<string>(s1, s2)"] -->|"Compile-time"| D["T = string\nstring temp = s1;\ns1 = s2;\ns2 = temp;"]1.2 Real-World Analogy: Kathmandu Traffic Routes
Imagine Kathmandu’s traffic system:
- Without templates: Separate "routes" for buses, cars, and motorcycles (duplicate code).
- With templates: One
Route<T>class that works for any vehicle type, reducing errors and maintenance.
2. Function Templates: Writing Generic Functions
2.1 Syntax and Instantiation
A function template defines a family of functions parameterized by a type T:
template <typename T> // or: template <class T>
T max(T a, T b) {
return (a > b) ? a : b;
}
How it works:
- Declaration:
template <typename T>tells the compiler to generate a function for any typeT. - Instantiation: When you call
max(3, 5)ormax("hello", "world"), the compiler creates a new version ofmaxforintandconst char*.
Visual: Compile-time instantiation:
flowchart TD
A["max(3, 5)"] --> B["T = int\nint max(int, int) { ... }"]
C["max(\"a\", \"b\")"] --> D["T = const char*\nconst char* max(const char*, const char*) { ... }"]2.2 Worked Example: Generic printArray
Task: Write a function to print any array (of int, double, string, etc.).
Solution:
#include <iostream>
template <typename T>
void printArray(T arr[], int size) {
for (int i = 0; i < size; i++) {
std::cout << arr[i] << " ";
}
}
Trace:
| Step | T Type |
arr Content |
Output |
|---|---|---|---|
| 1 | int |
{1, 2, 3} |
1 2 3 |
| 2 | double |
{1.1, 2.2} |
1.1 2.2 |
| 3 | string |
{"a", "b"} |
a b |
Real-World Tie-In:
- eSewa’s Order Queue: Imagine a generic
Queue<T>template used to manage orders for electricity bills, license renewals, or vehicle registration. The same queue logic works for all types.
3. Class Templates: Generic Data Structures
3.1 Defining a Class Template
A class template creates a family of classes (e.g., Stack<int>, Stack<string>):
template <typename T>
class Stack {
private:
T *arr;
int top;
int capacity;
public:
Stack(int size) { ... }
void push(T x) { ... }
T pop() { ... }
};
Visual: Stack<T> for int vs. string:
flowchart TD
A["Stack<int> s1;"] --> B["T = int\nint* arr;"]
C["Stack<string> s2;"] --> D["T = string\nstring* arr;"]3.2 Worked Example: Generic Stack Implementation
Code:
template <typename T>
class Stack {
private:
T *arr;
int top;
public:
Stack(int size) {
arr = new T[size];
top = -1;
}
void push(T x) {
arr[++top] = x;
}
T pop() {
return arr[top--];
}
};
Trace: Pushing int and string:
| Operation | Stack<int> State |
Stack<string> State |
|---|---|---|
push(5) |
arr = [5], top = 0 |
— |
push("hi") |
— | arr = ["hi"], top = 0 |
Real-World Tie-In:
- Pathao’s Ride Queue: A
Queue<RideRequest>template manages ride requests for bikes, cars, and auto-rickshaws. The same queue logic applies to all request types.
4. Template Specialization: Customizing for Specific Types
4.1 Why Specialize?
Sometimes, the generic version doesn’t work for all types (e.g., std::string needs special handling).
Example: Override max for std::string to compare lengths:
template <>
const char* max<const char*>(const char* a, const char* b) {
return (strlen(a) > strlen(b)) ? a : b;
}
Visual: Specialization vs. generic:
flowchart TD
A["max(\"hello\", \"world\")"] --> B["Generic:\nCompare chars\nResult: \"world\""]
C["max<const char*>()"] --> D["Specialized:\nCompare lengths\nResult: \"hello\""]4.2 Partial Specialization (Advanced)
For complex types (e.g., pairs), you can specialize partially:
template <typename T1, typename T2>
class Pair {
// Generic implementation
};
template <typename T>
class Pair<T, T> { // Specialization for same types
// Custom logic
};
5. Generic Programming with STL
5.1 The Standard Template Library (STL)
STL uses templates heavily for containers (vector<T>, map<K,V>) and algorithms (sort, find).
Example: std::vector works for any type:
#include <vector>
std::vector<int> nums = {1, 2, 3};
std::vector<std::string> names = {"Alice", "Bob"};
5.2 Worked Example: Generic sort
Code:
#include <algorithm>
template <typename RandomIt>
void sort(RandomIt first, RandomIt last) {
// Implementation uses template metaprogramming
}
Trace: Sorting int and string:
| Input | Output (sort) |
|---|---|
{3, 1, 2} |
{1, 2, 3} |
{"banana", "apple"} |
{"apple", "banana"} |
Real-World Tie-In:
- NEPSE Stock Data: A
map<string, double>template stores stock symbols (e.g.,"NTC","NBL") and their prices, sorted alphabetically or by value.
6. Type Deduction: auto and decltype
6.1 auto in Templates
Simplifies template usage by letting the compiler deduce types:
template <typename T>
auto add(T a, T b) -> decltype(a + b) {
return a + b;
}
Example:
auto x = add(3, 5); // x is int
auto y = add(1.1, 2.2); // y is double
6.2 decltype
Returns the type of an expression (used in templates for return types):
template <typename T>
decltype(T{} + T{}) add(T a, T b) {
return a + b;
}
7. Common Pitfalls and Best Practices
7.1 Pitfalls
| Mistake | Fix |
|---|---|
Forgetting <> in calls |
Stack<int> s; (not Stack<int> s()) |
| Mixing templates with pointers | Use T* or std::shared_ptr<T> |
| Overusing templates | Prefer non-templates for simple cases |
7.2 Best Practices
- Use
typename: Always usetypename T(notclass T) in templates. - Document templates: Clearly state which types a template supports.
- Prefer STL: Use
vector<T>,map<K,V>instead of reinventing wheels.
In the Real World
Khalti’s Transaction Logs:
- Uses
vector<Transaction>whereTransactionis a struct withstring userID,double amount, andstring status. - The same
vectorlogic works for deposits, transfers, and withdrawals.
- Uses
Daraz’s Order Processing:
- A
Queue<Order>template manages orders for electronics, groceries, and fashion. - The queue’s
enqueue()anddequeue()methods work identically for all product types.
- A
NTC’s Network Packet Handling:
- A
map<IPAddress, Packet>template routes packets to different devices. - The
mapautomatically sorts IPs, optimizing lookup time.
- A
Exam Tip
What Examiners Look For
Syntax: Know the exact syntax for:
- Function templates:
template <typename T> retType func(T param); - Class templates:
template <typename T> class Name { ... }; - Template instantiation:
Stack<string> s;
- Function templates:
Instantiation: Explain how
Tis replaced with actual types at compile-time.STL Connection: Relate templates to STL containers/algorithms (e.g.,
vector<T>,sort).Specialization: Know when and how to specialize templates (e.g., for
std::string).Pitfalls: Be ready to spot errors like:
- Missing
<>in template calls. - Incorrect type deduction.
- Missing
Common Exam Questions
"How does a function template differ from a regular function?" → Templates generate multiple functions at compile-time; regular functions are fixed.
"Write a class template for a
Queue<T>." → Includeenqueue(T),dequeue(), and aT* arrmember."Explain template specialization with an example." → Show how to override
maxforstd::stringto compare lengths.
Marks Distribution
| Topic | Marks (Approx.) |
|---|---|
| Function templates | 2–3 |
| Class templates | 3–4 |
| STL and templates | 2 |
| Specialization | 2 |
| Pitfalls/Code | 3 |
Final Note: Templates are compile-time magic—they let you write one piece of code that works for many types. Master the syntax, understand instantiation, and always tie examples to real-world apps (like Khalti, Daraz, or NTC). Practice writing Stack<T>, Queue<T>, and generic functions to ace this unit!
Based on the TU BSc CSIT syllabus for Object Oriented Programming (CSC166), unit 8.
Discussion
Loading…