07 Templates & Generic Programming
Overview: Compile-Time Polymorphism
Templates are C++‘s system for generic programming. Unlike Java or C# generics (which use runtime type erasure), C++ templates are evaluated entirely at compile time, generating dedicated, optimized machine code for each type used.
1. Template Instantiation Mechanics
When you define a template class or function, the compiler does not generate any machine code. Code is only generated when you instantiate the template with concrete parameters.
template<class T>
class Box {
T data;
};
Box<int> intBox; // Compiler generates code for Box<int>
Box<double> dBox; // Compiler generates code for Box<double>The Compile-time Substitution:
- Zero Runtime Overhead: There is no runtime cost; the generated assembly for
Box<int>is as fast as a class manually written for integers. - Header-Only Rule: Because the compiler must generate concrete type variations during compilation, the entire template definition must be available in every translation unit (source file) that instantiates it. Therefore, template classes and functions are written entirely in header files.
- Code Bloat: Instantiating a template with many different types increases the binary executable size.
2. Duck Typing in Function Templates
Function templates support Implicit Interfaces (often referred to as compile-time duck typing: “if it barks like a duck, it’s a duck”).
template<class T>
void triggerBark(const T& input) {
input.bark(); // The compiler checks if type T has a bark() method
}Unlike object-oriented polymorphism (which requires T to inherit from a base Dog class), templates only require that the operations used within the template are supported by T. If T has a bark() method, it compiles successfully.
3. Non-Type Template Parameters
Template parameters can be values instead of types. This is commonly used for fixed-size configurations (like static array boundaries) resolved at compile-time.
template<int Size>
class StaticBuffer {
char data[Size]; // Stack allocation of exact compile-time size
};4. Explicit Template Specialization
You can override a template’s default behavior for a specific type to implement custom optimizations.
// General template
template<typename T>
void print(T val) { std::cout << "General: " << val << '\n'; }
// Explicit specialization for double
template<>
void print<double>(double val) { std::cout << "Specialized double: " << val << '\n'; }💻 Conceptual Code Demonstration
#include <iostream>
// 1. Class Template
template<typename T>
class StackBuffer {
T data[10];
int top = -1;
public:
void push(const T& val) {
if (top < 9) data[++top] = val;
}
T pop() {
return (top >= 0) ? data[top--] : T();
}
};
// 2. Function Template with Duck Typing
template<typename T>
void executeAction(const T& obj) {
obj.perform(); // Compile-time check
}
class Actor {
public:
void perform() const { std::cout << "Acting!\n"; }
};
// 3. Non-type template parameter
template<int N>
void repeatPrint(const char* message) {
for (int i = 0; i < N; ++i) {
std::cout << message << '\n';
}
}
int main() {
// Instantiates StackBuffer<int> class
StackBuffer<int> myStack;
myStack.push(45);
// Instantiates executeAction<Actor>
Actor a;
executeAction(a);
// Instantiates repeatPrint<3>
repeatPrint<3>("Hello Templates");
return 0;
}