Introduction
Templates in C++ are a powerful feature that enables generic programming, allowing functions and classes to operate with generic types. Rather than writing separate code for different data types (like int, float, etc.), templates allow you to write a single function or class that works for any data type. This improves code reusability, maintainability, and type safety. Templates are extensively used in the Standard Template Library (STL) to define containers and algorithms. C++ supports two types of templates: function templates and class templates. Advanced forms include template specialization and variadic templates, enabling highly flexible and scalable programming solutions.
Function Templates
Function templates allow the creation of a single function that can work with different data types. This is achieved using a generic type parameter (like T) that is replaced with actual types during compilation.
Syntax:
template <typename T>
T add(T a, T b) {
return a + b;
}
Example:
#include <iostream>
using namespace std;
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
cout << “Int: ” << add(3, 4) << endl;
cout << “Float: ” << add(3.5f, 2.5f) << endl;
return 0;
}
Class Templates
Class templates in C++ enable writing generic classes that work with any data type using placeholder types like typename T. They eliminate code duplication and improve maintainability across type variations. Commonly used in STL containers like vector<T>, map<T>, or user-defined structures. Syntax begins with template<typename T> class MyClass { … };.
Syntax:
template <class T>
class Box {
T value;
public:
Box(T val) : value(val) {}
void show() {
cout << “Value: ” << value << endl;
}
};
Example:
#include <iostream>
using namespace std;
template <class T>
class Box {
T value;
public:
Box(T val) : value(val) {}
void show() {
cout << “Value: ” << value << endl;
}
};
int main() {
Box<int> intBox(10);
Box<string> strBox(“C++”);
intBox.show();
strBox.show();
return 0;
}
Template Specialization
Template specialization in C++ lets you define a modified version of a generic template for a specific data type. It overrides the default behavior to handle type-specific logic or optimizations. Syntax: template<> class MyClass<int> { /* specialized code */ }; Useful when a generic class or function doesn’t suit all types equally.
Syntax:
template <class T>
class Printer {
public:
void print(T data) {
cout << “Data: ” << data << endl;
}
};
// Specialization for char*
template <>
class Printer<char*> {
public:
void print(char* data) {
cout << “String: ” << data << endl;
}
};
Example:
#include <iostream>
using namespace std;
template <class T>
class Printer {
public:
void print(T data) {
cout << “Data: ” << data << endl;
}
};
template <>
class Printer<char*> {
public:
void print(char* data) {
cout << “String: ” << data << endl;
}
};
int main() {
Printer<int> p1;
Printer<char*> p2;
p1.print(42);
p2.print(“Hello Templates!”);
return 0;
}
Variadic Templates
Variadic templates in C++ enable functions or classes to handle any number of template parameters, introduced in C++11. They are especially useful for designing flexible utilities like std::tuple, type-safe logging, and format functions. Syntax involves parameter packs (typename… Args) and recursion or fold expressions for unpacking.
Syntax:
template<typename T>
void print(T arg) {
cout << arg << ” “;
}
template<typename T, typename… Args>
void print(T first, Args… rest) {
cout << first << ” “;
print(rest…);
}
Example:
#include <iostream>
using namespace std;
template<typename T>
void print(T arg) {
cout << arg << endl;
}
template<typename T, typename… Args>
void print(T first, Args… rest) {
cout << first << “, “;
print(rest…);
}
int main() {
print(1, 2.5, “C++”, ‘A’);
return 0;
}
Advantages of Templates
- Code Reusability: Templates let you write one function or class that works with multiple data types—reducing repetition.
- Type Safety: They catch type errors during compilation, increasing reliability and minimizing runtime issues.
- Flexibility: You can build generic algorithms and structures that adapt to different types.
- Standard Library Support: STL heavily relies on templates, powering vector, map, set, and more.
- Performance: Since instantiation happens at compile-time, templates can be inlined for speed.
Disadvantages of Templates
- Complex Errors: Compiler messages for template errors can be dense and hard to decode.
- Code Bloat: Multiple instantiations may generate large binaries due to duplicated code.
- Limited Tooling Support: IDEs might lag or misinterpret logic when working with heavy template code.
- Longer Compilation Times: Instantiating templates for various types increases compile duration.
Applications of Templates
- STL Containers: Classes like vector, stack, map use templates to support any datatype.
- Generic Algorithms: Functions such as sort, search work with different container types.
- Utility Libraries: Reusable code modules in C++ often rely on templates for flexibility.
- Type-Safe Structures: Linked lists, trees, and graphs can be template-based for type safety.
- Math Computations: Operations on int, float, double etc. are simplified with templates.
Limitations of Templates
- No Partial Function Specialization: Only class templates support partial specialization.
- Verbose Errors: Debugging is tricky due to lengthy, nested error messages.
- Not Ideal for Small Tasks: For one-off logic, templates may be overkill and reduce clarity.
No Runtime Polymorphism: Templates resolve types at compile time, not suitable for dynamic dispatch