Introduction: What Are Generics in C++ and Why Are They Needed
In the world of modern programming, code reuse is one of the key principles. If you write a summation function for int, and then for double and float, sooner or later you will want to avoid duplication. This is where generics (generic programming) come to the rescue. In C++, this concept is implemented through templates.
Generics allow you to write code that works with any data type without sacrificing performance (unlike virtual functions or void*). The compiler generates a separate version of a function or class for each specific type, providing maximum execution speed.
In this article, we will break down why generics are needed in C++, how to properly declare and use them in practice, and also look at typical mistakes and advanced techniques.
Basic Syntax: How to Declare and Use a Template
A template in C++ is declared using the keyword template and angle brackets <>, inside which a type parameter (usually typename or class) is specified.
Function Template
The simplest example is a function that returns the maximum of two values:
template <typename T>T max(T a, T b) { return (a > b) ? a : b;}
// Usage:int main() { std::cout << max(3, 7) << std::endl; // 7 std::cout << max(3.14, 2.71) << std::endl; // 3.14 std::cout << max('a', 'z') << std::endl; // z return 0;}Note: the compiler deduces the type T based on the passed arguments. If you need to explicitly specify the type, you can write max<double>(3.14, 2.71).
Class Template
Templates also work with classes. A classic example is a simple "pair" container:
template <typename T1, typename T2>class Pair {private: T1 first; T2 second;public: Pair(T1 f, T2 s) : first(f), second(s) {} T1 getFirst() const { return first; } T2 getSecond() const { return second; }};
// Usage:Pair<int, std::string> student(1, "Alice");std::cout << student.getFirst() << " " << student.getSecond();Here T1 and T2 are template parameters that can be any types.
Practical Examples: From Simple Containers to Algorithms
Let's look at several real-world scenarios where generics are indispensable.
Universal Sorting
Let's write a template function for sorting an array of any type that supports the < operator:
template <typename T>void bubbleSort(T arr[], int n) { for (int i = 0; i < n - 1; ++i) for (int j = 0; j < n - i - 1; ++j) if (arr[j] > arr[j + 1]) std::swap(arr[j], arr[j + 1]);}
// Example:int intArr[] = {5, 2, 8, 1};bubbleSort(intArr, 4); // Works with int
double dblArr[] = {3.14, 2.71, 1.41};bubbleSort(dblArr, 3); // Works with doubleStack with an Arbitrary Data Type
Let's implement a simple stack based on a template:
template <typename T>class Stack {private: std::vector<T> elements;public: void push(const T& value) { elements.push_back(value); } void pop() { if (!elements.empty()) elements.pop_back(); } T top() const { return elements.back(); } bool empty() const { return elements.empty(); }};
// Usage:Stack<int> intStack;intStack.push(10);intStack.push(20);std::cout << intStack.top(); // 20"Find and Replace" Algorithm
A template function that replaces all occurrences of one value with another in a container:
templa