Object Oriented ProgrammingUnit 1010 min read
Templates & Namespaces: Code Reuse & Organization in C++
Unit 10 of Object Oriented Programming explores how to write flexible, reusable code using templates (generic functions/classes) and namespaces (organizing code to avoid conflicts), with real-world examples from Nepalese apps like eSewa and Kathmandu traffic routing.
TAKEAWAYS:
- Templates let you write one function/class that works with any data type (e.g.,
swap<T>forint,string, or custom objects). - Namespaces prevent naming collisions (e.g.,
std::coutvs. your owncoutfunction). - Function templates vs. class templates: the former generate functions at compile-time; the latter generate entire classes.
- Default template arguments simplify syntax (e.g.,
vector<int>instead ofvector<T,int>). - Namespace pollution happens when too many
using namespacedirectives are used; prefer explicit scoping. - SFINAE (Substitution Failure Is Not An Error) is an advanced technique to enable/disable templates based on type traits.
1. Why Do We Need Templates?
In C++, functions and classes are hardcoded for specific types. For example, to swap two ints and two doubles, you’d write two separate swap() functions. Templates solve this by creating generic code that works for any type.
1.1 Function Templates
A function template defines a pattern for a function that can operate on different data types. The compiler generates the actual function at compile-time based on the type used.
Syntax:
template <typename T> // or 'template <class T>'
T swap(T a, T b) {
T temp = a;
a = b;
b = temp;
}
How it works:
flowchart TD
A["User calls: swap<int>(x, y)"] --> B["Compiler sees template"]
B --> C["Generates:\nint swap(int a, int b) { ... }"]
C --> D["Executes with x and y"]Example: Swapping Two Values
#include <iostream>
using namespace std;
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
int main() {
int x = 5, y = 10;
double p = 3.14, q = 2.71;
cout << max(x, y) << endl; // Output: 10
cout << max(p, q) << endl; // Output: 3.14
return 0;
}
Trace Table:
| Step | max<int>(5, 10) |
max<double>(3.14, 2.71) |
|---|---|---|
| 1 | Compares 5 > 10 → false |
Compares 3.14 > 2.71 → true |
| 2 | Returns 10 |
Returns 3.14 |
Real-World Use:
- eSewa’s Payment System
eSewa uses templates to handle transactions for any currency type (NPR, USD, INR). The same
processPayment<T>()function works forint(NPR in paise) ordouble(USD with decimals).template <typename Currency> void processPayment(Currency amount) { // Logic to deduct from wallet }
2. Class Templates
Class templates generalize entire classes. For example, std::vector<T> works for int, string, or custom objects.
classDiagram
class Box~T~ {
+T content
+void set(T val)
+T get()
}
class Stack~T~ {
-T* arr
-int top, size
+void push(T val)
+T pop()
}
Box --> Stack : "Uses template pattern"Syntax:
template <typename T>
class Box {
private:
T content;
public:
void set(T val) { content = val; }
T get() { return content; }
};
Example: A Generic Stack
#include <iostream>
using namespace std;
template <typename T>
class Stack {
private:
T* arr;
int top, size;
public:
Stack(int s) : size(s), top(-1) { arr = new T[size]; }
void push(T val) { arr[++top] = val; }
T pop() { return arr[top--]; }
};
int main() {
Stack<int> intStack(5);
intStack.push(10);
cout << intStack.pop() << endl; // Output: 10
Stack<string> strStack(3);
strStack.push("Hello");
cout << strStack.pop() << endl; // Output: Hello
return 0;
}
State After Each Operation:
Real-World Use:
- Khalti’s Order Queue
Khalti uses a
Queue<Order>template to manage pending transactions. The same queue logic works forOrder<int>(NPR amounts) orOrder<double>(USD amounts).template <typename Amount> class OrderQueue { // Processes orders of any currency type };
3. Default Template Arguments
Simplify syntax by providing default types. For example:
template <typename T = int>
class Container {
// Defaults to int if no type is given
};
Example: A Flexible Pair Class
template <typename T1 = int, typename T2 = double>
class Pair {
private:
T1 first;
T2 second;
public:
Pair(T1 f, T2 s) : first(f), second(s) {}
void display() { cout << first << ", " << second << endl; }
};
int main() {
Pair<> p1(10, 3.14); // Uses defaults: int, double
Pair<string, char> p2("Hello", 'A');
p1.display(); // Output: 10, 3.14
p2.display(); // Output: Hello, A
return 0;
}
4. Namespaces: Organizing Code
Namespaces group related code to avoid naming conflicts. For example, std::cout vs. your own cout.
Syntax:
namespace MyMath {
int add(int a, int b) { return a + b; }
}
namespace YourMath {
int add(int a, int b) { return a * b; } // Different logic!
}
How to Use:
using namespace MyMath; // Now 'add' refers to MyMath::add
cout << add(2, 3); // Output: 5 (not 6!)
Real-World Use:
- NTC’s Traffic Management System
NTC uses namespaces to separate:
NTC::TrafficLight(controls signals)NTC::Fines(calculates penalties) Avoids conflicts with other city systems.
5. Namespace Pollution vs. Explicit Scoping
| Problem | Solution |
|---|---|
using namespace std; everywhere → conflicts |
Use std::cout, std::vector explicitly |
Too many using directives |
Prefer using std::cout; (specific) |
Example: Bad vs. Good Practice
// BAD: Pollutes global namespace
using namespace std;
using namespace MyLib;
// GOOD: Explicit scoping
std::cout << "Hello";
MyLib::process();
6. Advanced: SFINAE (Substitution Failure Is Not An Error)
SFINAE lets you enable/disable templates based on type traits. For example:
template <typename T, typename = void>
struct is_arithmetic : std::false_type {};
template <typename T>
struct is_arithmetic<T, std::void_t<std::declval<T>() + std::declval<T>()>>
: std::true_type {};
Use Case:
template <typename T, typename = std::enable_if_t<is_arithmetic<T>::value>>
T add(T a, T b) {
return a + b; // Only works for arithmetic types
}
7. Comparison: Function vs. Class Templates
| Feature | Function Template | Class Template |
|---|---|---|
| Purpose | Generic functions | Generic classes |
| Example | swap<T>(a, b) |
vector<T> |
| Generated By | Compiler at compile-time | Compiler at compile-time |
| Use Case | Utility functions | Data structures (stack, queue) |
8. Common Pitfalls & Fixes
- Forgetting to Specify Template Arguments
// WRONG: Compiler won’t know T!
swap(a, b); // Error: 'swap' is ambiguous
```figure
{"type":"hash-table","buckets":[[{"key":"int","value":"swap(10, 20)"}],[],[{"key":"double","value":"swap(3.14, 2.71)"}],[{"key":"string","value":"swap(\"A\", \"B\")"}]],"caption":"Template instantiation for different types (default `T` unspecified)"}
// FIX: Explicitly specify
swap<int>(a, b);
2. Templates in Headers
Always declare templates in header files (.h) because they generate multiple versions.
## In the Real World
eSewa’s Wallet System Uses
template <typename Currency>to handle transactions in NPR, USD, or INR without rewriting logic.template <typename C> void deductBalance(C amount) { // Works for int (NPR), double (USD) }Khalti’s Order Processing Employs
Queue<Order<T>>to manage pending transactions, whereTcan beint(NPR) orstring(order ID).NTC’s Traffic Light Controller Uses namespaces to separate:
NTC::TrafficLight(controls signals)NTC::Fines(calculates penalties) Avoids conflicts with Kathmandu Metropolitan City’s systems.
Nepal Stock Exchange (NEPSE) Data Analysis Uses
std::vector<Stock<T>>to store stock prices (Tcan befloatfor NEPSE index ordoublefor foreign stocks).
## Exam Tip
Templates Are Compile-Time Magic
- The compiler generates code for each type used. No runtime overhead.
- Example:
vector<int>andvector<double>are separate classes in memory.
Namespace Questions
- Always prefer
std::coutoverusing namespace std;. - Expect questions on scope resolution (
::) and namespace collisions.
- Always prefer
Trace Tables Are Key
- For template functions, show how the compiler substitutes types (e.g.,
swap<int>vs.swap<double>).
- For template functions, show how the compiler substitutes types (e.g.,
Common Exam Patterns
- Define a template function given a scenario (e.g., "Write a template to find the max of two values").
- Debug namespace conflicts (e.g., "Why does this code fail?").
- Explain SFINAE in 1-2 lines (mention "compile-time type checking").
Code Snippets
- Memorize the syntax for:
- Function templates (
template <typename T>) - Class templates (
template <class T> class X { ... }) - Default arguments (
template <typename T = int>)
- Function templates (
- Memorize the syntax for:
In the real world
- eSewa’s Payment System: Uses function templates (
processPayment<T>) to handle transactions in NPR (int), USD (double), or INR (float) without rewriting logic for each currency type. - Khalti’s Order Queue: Employs class templates (
Queue<Order<T>>) to manage pending transactions, whereTcan beint(NPR amounts) ordouble(USD amounts), ensuring type safety. - NTC’s Traffic Light System: Leverages namespaces (
NTC::TrafficLight,NTC::Fines) to avoid naming conflicts with other city management systems, ensuring modularity and maintainability.
Based on the TU BIT syllabus for Object Oriented Programming (BIT153), unit 10.
Discussion
Loading…