Article by Ayman Alheraki on January 11 2026 10:33 AM
Introduction
Templates are a cornerstone of modern C++ programming, providing powerful mechanisms for generic programming. They enable code to be written in a way that is independent of data types, facilitating reusability and type safety. This article explores function and class templates in detail, illustrating how they contribute to modern polymorphism in C++.
Templates in C++ allow functions and classes to operate with generic types. They enable developers to write code that can work with any data type without being rewritten for each type. Templates are a core feature of modern C++ and are widely used to create generic and reusable components.
Function templates allow you to define a function in a generic way. The syntax for a function template involves defining the function with template parameters.
Here’s a simple example of a function template that returns the maximum of two values:
// Function template for finding the maximum of two valuestemplate <typename T>T maximum(T a, T b) { return (a > b) ? a : b;}
int main() { std::cout << "Maximum of 3 and 5: " << maximum(3, 5) << std::endl; std::cout << "Maximum of 3.5 and 2.1: " << maximum(3.5, 2.1) << std::endl; std::cout << "Maximum of 'A' and 'B': " << maximum('A', 'B') << std::endl; return 0;}In this example, maximum is a template function that works with any data type provided the type supports comparison operators.
Function template specialization allows you to define specific behavior for a particular type. This is useful when the generic implementation doesn’t fit all types.
// Primary templatetemplate <typename T>void print(T value) { std::cout << "Generic value: " << value << std::endl;}
// Specialization for char* (C-style strings)template <>void print<char*>(char* value) { std::cout << "C-style string: " << value << std::endl;}
int main() { print(10); print(3.14); char str[] = "Hello, World!"; print(str); return 0;}In this example, the print function is specialized for char*, providing different behavior for C-style strings compared to other types.
Class templates allow you to create classes that can operate with any data type. They are similar to function templates but are used for creating generic classes.
Here’s a simple example of a class template for a Box:
// Class template for a Boxtemplate <typename T>class Box {private: T value;
public: Box(T v) : value(v) {}
T getValue() const { return value; }
void setValue(T v) { value = v; }};
int main() { Box<int> intBox(123); Box<double> doubleBox(456.78);
std::cout << "Integer Box contains: " << intBox.getValue() << std::endl; std::cout << "Double Box contains: " << doubleBox.getValue() << std::endl;
return 0;}In this example, Box is a template class that can hold a value of any type specified when the Box object is created.
Class template specialization allows for different implementations of a class template for specific types.
// Primary templatetemplate <typename T>class Storage {public: void display() { std::cout << "Generic storage" << std::endl; }};
// Specialization for inttemplate <>class Storage<int> {public: void display() { std::cout << "Storage for integers" << std::endl; }};
int main() { Storage<double> genericStorage; Storage<int> intStorage;
genericStorage.display(); // Outputs: Generic storage intStorage.display(); // Outputs: Storage for integers
return 0;}In this example, the Storage class is specialized for int, providing different behavior for integer storage.
With C++20 and later, concepts and constraints have been introduced to enhance template programming by adding constraints to template parameters. Concepts allow you to specify requirements for template arguments, improving code readability and compiler error messages.
// Define a concepttemplate <typename T>concept Addable = requires(T a, T b) { { a + b } -> std::same_as<T>;};
// Function template with concepttemplate <Addable T>T add(T a, T b) { return a + b;}
int main() { std::cout << "Sum of 3 and 5: " << add(3, 5) << std::endl; std::cout << "Sum of 3.5 and 2.1: " << add(3.5, 2.1) << std::endl; // The following line will cause a compile-time error // std::cout << "Sum of string and integer: " << add(std::string("Hello"), 3) << std::endl;
return 0;}In this example, the Addable concept ensures that only types that support the + operator can be used with the add function template.
Use Templates Wisely: Avoid overusing templates as they can make code harder to read and maintain. Use them where they provide clear benefits.
Prefer Type Traits for Type Information: Use type traits for type-related operations rather than relying solely on template specialization.
Document Template Requirements: Clearly document the expected requirements and behavior for template parameters.
Use Concepts for Better Readability: Leverage concepts to enforce constraints and improve code readability and error reporting.
Templates are a powerful feature of modern C++ that enable generic programming and promote code reuse. Function and class templates allow developers to write flexible and type-safe code, while template specialization and concepts provide advanced capabilities for customizing and constraining template behavior. By understanding and applying these features effectively, you can create more efficient, maintainable, and robust C++ programs.