Object Oriented Programming in C++Unit 1013 min read
Templates & Generic Programming: Functions, Classes, STL
Unit 10 of Object Oriented Programming in C++ covers function templates, class templates, and generic programming to write reusable code for any data type, with applications in containers (vector, list) and algorithms (sort, search) from the Standard Template Library (STL).
TAKEAWAYS:
- Generic code lets you write one function/class that works for
int,float, or custom types without rewriting. - Function templates use
<T>to create functions that adapt to any data type (e.g.,swap<T>(a, b)). - Class templates define reusable containers like
vector<T>ormap<K,V>that store any type. - STL algorithms (e.g.,
sort,find) work generically on any container (array, list, vector). - Type deduction lets the compiler infer template parameters from arguments (e.g.,
auto x = 5;→int). - Specializations override default template behavior for specific types (e.g.,
vector<bool>uses bits).
1. Why Generic Programming?
Problem with Procedure-Oriented Code
In C-style functions, you must write separate versions for each data type:
void swapInt(int &a, int &b) { int t = a; a = b; b = t; }
void swapFloat(float &a, float &b) { float t = a; a = b; b = t; }
Disadvantages:
- Code duplication: Same logic repeated for every type.
- Maintenance: Fixing a bug requires editing all versions.
- Limited flexibility: Cannot handle custom types (e.g.,
swapforStudentobjects).
Solution: Templates
Templates let you write one function/class that works for any type. The compiler generates specialized versions as needed.
2. Function Templates
Syntax
template <typename T> // or 'class T' (same meaning)
return_type function_name(parameters) {
// body using T
}
Example: Generic swap function
template <typename T>
void swap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
How it works:
- The compiler replaces
Twith the actual type (e.g.,int,float) when called. - No runtime overhead—just like a regular function.
Example: Generic max Function
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
Trace:
| Call | Compiler Generates | Output |
|---|---|---|
max(3, 5) |
int max(int, int) |
5 |
max(3.2, 5.1) |
double max(double, double) |
5.1 |
max("A", "B") |
const char* max(...) |
"B" |
Real-World Use: STL Algorithms
The Standard Template Library (STL) uses templates for algorithms like:
sort(): Works onvector<int>,list<string>, etc.find(): Searches in any container.accumulate(): Sums elements of any iterable type.
Example: Sorting a vector of Student objects (custom type).
#include <algorithm>
#include <vector>
using namespace std;
struct Student {
string name;
int roll;
bool operator<(const Student &s) const {
return roll < s.roll;
}
};
int main() {
vector<Student> students = {{"Alice", 101}, {"Bob", 102}};
sort(students.begin(), students.end()); // Uses template <typename Iter>
return 0;
}
3. Class Templates
Syntax
template <typename T>
class ClassName {
// members using T
};
Example: Generic Stack class
template <typename T>
class Stack {
private:
vector<T> data;
public:
void push(T item) { data.push_back(item); }
T pop() { T top = data.back(); data.pop_back(); return top; }
};
Usage:
Stack<int> intStack; // Stack of integers
Stack<string> strStack; // Stack of strings
State After Operations
Stack Operations Visualized
4. Template Specialization
When to Use
Override default template behavior for specific types (e.g., optimize vector<bool> to use bits).
Example: Specializing max for string
template <> // Specialization for string
string max<string>(string a, string b) {
return (a.length() > b.length()) ? a : b;
}
Trace:
| Call | Uses Specialization? | Output |
|---|---|---|
max(3, 5) |
No | 5 (int) |
max("hello", "hi") |
Yes | "hello" |
5. Non-Type Template Parameters
Templates can also use non-type parameters (e.g., size_t for array sizes):
template <size_t N>
class FixedArray {
int data[N];
public:
void set(int index, int value) { data[index] = value; }
};
Use Case: Fixed-size arrays with compile-time bounds (e.g., FixedArray<100>).
6. Standard Template Library (STL) Containers
STL provides generic containers using templates:
| Container | Description | Example Usage |
|---|---|---|
vector<T> |
Dynamic array | vector<int> nums; |
list<T> |
Doubly linked list | list<string> names; |
map<K,V> |
Key-value pairs (sorted) | map<int, string> dict; |
set<T> |
Unique elements (sorted) | set<float> uniqueValues; |
queue<T> |
FIFO queue | queue<Task> taskQueue; |
Example: vector Internals
flowchart TD
A["vector<int> v(5);"] --> B["Allocated: [_, _, _, _, _] (capacity=5, size=0)"]
B --> C["v.push_back(10)"]
C --> D["State: [10, _, _, _, _] (size=1)"]
D --> E["v.push_back(20)"]
E --> F["State: [10, 20, _, _, _] (size=2)"]
F --> G["v.resize(10)"]
G --> H["State: [10, 20, _, _, _, _, _, _, _, _] (size=10, capacity=10)"]7. Type Deduction with auto and decltype
auto
Lets the compiler deduce the type:
auto x = 5; // int
auto y = 3.14; // double
auto z = vector<int>(); // vector<int>
decltype
Returns the type of an expression (used in templates):
template <typename T>
auto add(T a, T b) -> decltype(a + b) {
return a + b;
}
8. Advantages of Templates
| Advantage | Explanation |
|---|---|
| Code Reusability | Write once, use for any type. |
| Type Safety | Compiler checks type correctness. |
| Performance | No runtime overhead (inlined by compiler). |
| STL Integration | Works seamlessly with STL algorithms. |
| Extensibility | Customize behavior via specializations. |
9. Disadvantages/Limitations
| Limitation | Explanation |
|---|---|
| Compile-Time Overhead | Generates code for every type used. |
| Debugging Complexity | Template errors can be cryptic. |
| No Runtime Polymorphism | Templates are resolved at compile time. |
| Binary Size Bloat | Multiple instantiations increase executable size. |
In the Real World
eSewa (Nepal)
- Use:
map<string, User>stores user accounts (key: email, value:Userobject). - Why: Generic
maphandles any key-value pair without rewriting.
- Use:
Khalti’s Transaction System
- Use:
vector<Transaction>stores all transactions (customTransactionstruct). - Why: STL’s
sort()andfind()work on any iterable, includingvector<Transaction>.
- Use:
Pathao’s Ride Queue
- Use:
queue<RideRequest>manages pending ride requests (FIFO). - Why: Generic
queue<T>ensures type safety for any request type.
- Use:
Ncell’s Customer Database
- Use:
set<Customer>ensures unique customer IDs (sorted). - Why: STL’s
setautomatically handles uniqueness and ordering.
- Use:
Daraz’s Order Processing
- Use:
map<OrderID, Order>tracks orders by ID. - Why: Generic
mapadapts to anyOrderIDtype (e.g.,stringorint).
- Use:
Worked Example: Bank Loan Calculator
Problem: A bank wants a generic function to calculate loan interest for any numeric type (float, double, or custom Currency).
Solution: Use a template function with operator+ overloaded.
#include <iostream>
using namespace std;
template <typename T>
T calculateInterest(T principal, float rate, int years) {
return principal + (principal * rate * years / 100);
}
struct NepaliRupee {
float amount;
NepaliRupee operator+(NepaliRupee other) {
return {amount + other.amount};
}
};
int main() {
// Works for float
float loan1 = calculateInterest(100000.0f, 8.5f, 5);
cout << "Float loan: " << loan1 << endl;
// Works for custom type (if + is overloaded)
NepaliRupee loan2 = calculateInterest(NepaliRupee{100000}, 8.5f, 5);
cout << "Nepali Rupee loan: " << loan2.amount << endl;
return 0;
}
Output:
Float loan: 142500
Nepali Rupee loan: 142500
Exam Tip
Understand Template Syntax:
- Know when to use
typenamevs.class(they are equivalent). - Remember
<>for template arguments (e.g.,vector<int>).
- Know when to use
STL is Key:
- Memorize common containers (
vector,list,map) and algorithms (sort,find). - Explain how
sort()works generically on any iterable.
- Memorize common containers (
Trace Template Instantiation:
- For questions like "What does
max(3.5, 7.2)generate?", answer:double max(double, double)(compiler deducesT = double).
- For questions like "What does
Specialization vs. Overloading:
- Overloading: Same name, different parameters (compile-time).
void print(int x); // Overload 1 void print(double x); // Overload 2 - Specialization: Same template, different type (compile-time).
template <> void print<string>(string s); // Specialization
- Overloading: Same name, different parameters (compile-time).
Common Pitfalls:
- Missing
#include <vector>: Causes "vector not found" errors. - Forgetting
typename: Usevector<T>::iterator(notvector<T>::iteratorwithouttypename). - Non-copyable types: Templates assume types are copyable (e.g.,
unique_ptrneeds special handling).
- Missing
Practical Questions:
- Expect programs like:
- Generic
add()for two numbers. Stack<T>withpush()/pop().- Using
sort()on avectorof custom objects.
- Generic
- Always trace the template instantiation (e.g., what type
Tbecomes).
- Expect programs like:
Past Exam Question Analysis
Question: "Why is generic programming beneficial? Explain template functions with a simple program." Model Answer: Generic programming reduces code duplication and improves maintainability. Template functions allow writing a single function that works for multiple types, as shown below:
template <typename T>
T multiply(T a, T b) {
return a * b;
}
int main() {
cout << multiply(3, 4) << endl; // int
cout << multiply(3.5, 2.0) << endl; // double
return 0;
}
Trace:
| Call | Template Instantiation | Output |
|---|---|---|
multiply(3, 4) |
int multiply(int, int) |
12 |
multiply(3.5, 2) |
double multiply(double, double) |
7.0 |
Quick Revision Table
| Concept | Syntax Example | Use Case |
|---|---|---|
| Function Template | template <typename T> T add(T a, T b) |
Generic add(), swap() |
| Class Template | template <typename T> class Stack |
vector<T>, map<K,V> |
| Template Specialization | template <> int max<int>(int, int) |
Optimize for int |
| Non-Type Parameter | template <size_t N> class Array |
Fixed-size arrays |
auto |
auto x = 5; |
Type deduction |
| STL Algorithms | sort(v.begin(), v.end()) |
Sort any container |
In the real world
- Pathao/Daraz: Uses
std::sort(STL algorithm) to sort delivery orders by distance or time, ensuring efficient route planning for drivers. The genericsortworks onvector<Order>where eachOrderis a custom struct withdistance,time, andlocationfields. - Nepali Banks (e.g., NMB, Global IME): Employs
std::map(STL container) to store customer account details (key: account number, value:Accountstruct) for O(log n) lookup during transactions. Template specialization optimizesmap<bool>for flag checks (e.g.,is_active). - eSewa/Khalti: Leverages
std::queue(STL container) to manage pending transactions in FIFO order, ensuring fairness and preventing deadlocks during peak hours. The queue’s generic nature handles transactions of any type (Payment,Refund, etc.).
Based on the PU BE Computer (PU) syllabus for Object Oriented Programming in C++, unit 10.
Discussion
Loading…