Real-World Examples of Using Templates in C++

1. Standard Library Containers

Example: std::vector

The C++ Standard Library includes several container classes that are implemented as templates. One of the most commonly used container templates is std::vector. It provides a dynamic array that can store elements of any type.

Why Use Templates?

  • Flexibility: You can create a vector to hold any data type (integers, strings, custom objects, etc.).
  • Code Reusability: The same std::vector implementation works for all types, avoiding the need to write separate classes for each type.

Implementation Example:

#include <iostream>
#include <vector>

int main() {
    // Vector of integers
    std::vector<int> intVector = {1, 2, 3, 4, 5};

    // Vector of strings
    std::vector<std::string> stringVector = {"Hello", "World"};

    // Adding elements
    intVector.push_back(6);
    stringVector.push_back("!");

    // Accessing elements
    std::cout << intVector[0] << std::endl;      // Output: 1
    std::cout << stringVector[1] << std::endl;   // Output: World

    return 0;
}

In this example:

  • std::vector<int> creates a vector to store integers.
  • std::vector<std::string> creates a vector to store strings.
  • Both vectors use the same underlying implementation but handle different types.

2. Generic Algorithms

Example: std::sort

Many algorithms in the Standard Library, such as std::sort, are implemented as function templates. This allows them to work with any type that supports the required operations.

Why Use Templates?

  • Generality: The same sorting algorithm can be used for arrays or vectors of any type.
  • Efficiency: Template instantiation ensures that the sort operation is optimized for the specific type at compile-time.

Implementation Example:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {4, 2, 5, 1, 3};

    // Sorting the vector
    std::sort(numbers.begin(), numbers.end());

    // Displaying sorted elements
    for (int num : numbers) {
        std::cout << num << " ";
    }   // Output: 1 2 3 4 5

    return 0;
}

In this example:

  • std::sort is used to sort a vector of integers.
  • The same function can be used to sort vectors of other types, such as std::vector<std::string>.

3. Custom Data Structures

Example: Smart Pointers

Smart pointers, such as std::unique_ptr and std::shared_ptr, are implemented as class templates in the Standard Library. They provide automatic memory management for dynamically allocated objects, helping to prevent memory leaks and dangling pointers.

Why Use Templates?

  • Automatic Resource Management: Smart pointers manage the lifecycle of dynamically allocated objects, freeing memory automatically when it’s no longer needed.
  • Type Safety: The same smart pointer class can handle any type of object, ensuring type safety at compile-time.

Implementation Example:

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() { std::cout << "Constructor called" << std::endl; }
    ~MyClass() { std::cout << "Destructor called" << std::endl; }
    void display() { std::cout << "Hello from MyClass" << std::endl; }
};

int main() {
    // Using unique_ptr to manage a MyClass object
    std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();
    ptr->display();  // Output: Hello from MyClass

    // Automatically deletes the MyClass object when ptr goes out of scope
    return 0;
}

In this example:

  • std::unique_ptr<MyClass> manages the memory for a MyClass object.
  • The unique_ptr ensures that the MyClass object is automatically deleted when the smart pointer goes out of scope, preventing memory leaks.