Advanced C++ Features

Templates, STL, modern C++ features, and performance optimization

Templates and Generic Programming

Function and Class Templates

#include <iostream>
#include <vector>
#include <string>

// Function template
template<typename T>
T getMax(T a, T b) {
    return (a > b) ? a : b;
}

// Template with multiple parameters
template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) {  // C++11 trailing return type
    return a + b;
}

// Class template
template<typename T>
class Stack {
private:
    std::vector<T> elements;
    
public:
    void push(const T& element) {
        elements.push_back(element);
    }
    
    void pop() {
        if (!elements.empty()) {
            elements.pop_back();
        }
    }
    
    T& top() {
        return elements.back();
    }
    
    bool empty() const {
        return elements.empty();
    }
    
    size_t size() const {
        return elements.size();
    }
};

// Template specialization
template<>
class Stack<bool> {
private:
    std::vector<char> elements;  // Use char instead of bool for efficiency
    
public:
    void push(bool element) {
        elements.push_back(element ? 1 : 0);
    }
    
    void pop() {
        if (!elements.empty()) {
            elements.pop_back();
        }
    }
    
    bool top() {
        return elements.back() != 0;
    }
    
    bool empty() const {
        return elements.empty();
    }
    
    size_t size() const {
        return elements.size();
    }
};

int main() {
    // Function template usage
    std::cout << "Max of 10, 20: " << getMax(10, 20) << std::endl;
    std::cout << "Max of 3.14, 2.71: " << getMax(3.14, 2.71) << std::endl;
    std::cout << "Max of 'a', 'z': " << getMax('a', 'z') << std::endl;
    
    // Mixed type template
    std::cout << "Add 5 + 3.14: " << add(5, 3.14) << std::endl;
    
    // Class template usage
    Stack<int> intStack;
    intStack.push(10);
    intStack.push(20);
    intStack.push(30);
    
    std::cout << "Stack size: " << intStack.size() << std::endl;
    std::cout << "Top element: " << intStack.top() << std::endl;
    
    Stack<std::string> stringStack;
    stringStack.push("Hello");
    stringStack.push("World");
    
    while (!stringStack.empty()) {
        std::cout << stringStack.top() << " ";
        stringStack.pop();
    }
    std::cout << std::endl;
    
    return 0;
}

Standard Template Library (STL)

Containers, Iterators, and Algorithms

#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <algorithm>
#include <iterator>
#include <numeric>

int main() {
    // Containers
    std::vector<int> vec = {5, 2, 8, 1, 9, 3};
    std::list<std::string> lst = {"apple", "banana", "cherry"};
    std::map<std::string, int> ages = {{"Alice", 25}, {"Bob", 30}, {"Charlie", 35}};
    std::set<int> uniqueNumbers = {1, 2, 3, 2, 1, 4, 5};
    
    // Iterators
    std::cout << "Vector elements: ";
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    // Range-based for loop (C++11)
    std::cout << "List elements: ";
    for (const auto& item : lst) {
        std::cout << item << " ";
    }
    std::cout << std::endl;
    
    // Algorithms
    std::sort(vec.begin(), vec.end());
    std::cout << "Sorted vector: ";
    for (int n : vec) {
        std::cout << n << " ";
    }
    std::cout << std::endl;
    
    // Find algorithm
    auto found = std::find(vec.begin(), vec.end(), 5);
    if (found != vec.end()) {
        std::cout << "Found 5 at position: " << std::distance(vec.begin(), found) << std::endl;
    }
    
    // Transform algorithm
    std::vector<int> squared(vec.size());
    std::transform(vec.begin(), vec.end(), squared.begin(), [](int n) { return n * n; });
    
    std::cout << "Squared elements: ";
    for (int n : squared) {
        std::cout << n << " ";
    }
    std::cout << std::endl;
    
    // Accumulate
    int sum = std::accumulate(vec.begin(), vec.end(), 0);
    std::cout << "Sum: " << sum << std::endl;
    
    return 0;
}

Modern C++ Features (C++11/14/17/20)

Lambda Functions, Auto, and More

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <memory>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
    // Lambda functions (C++11)
    auto isEven = [](int n) { return n % 2 == 0; };
    auto square = [](int n) { return n * n; };
    
    // Count even numbers
    int evenCount = std::count_if(numbers.begin(), numbers.end(), isEven);
    std::cout << "Even numbers: " << evenCount << std::endl;
    
    // Lambda with capture
    int multiplier = 3;
    auto multiplyBy = [multiplier](int n) { return n * multiplier; };
    
    // Transform with lambda
    std::vector<int> multiplied(numbers.size());
    std::transform(numbers.begin(), numbers.end(), multiplied.begin(), multiplyBy);
    
    // Auto keyword (C++11)
    auto result = 42;  // int
    auto pi = 3.14159; // double
    auto name = std::string("C++");
    
    // Range-based for loop with auto
    for (const auto& num : multiplied) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    
    // Smart pointers (C++11)
    auto ptr = std::make_unique<int>(42);
    auto sharedPtr = std::make_shared<std::string>("Hello");
    
    std::cout << "Unique ptr: " << *ptr << std::endl;
    std::cout << "Shared ptr: " << *sharedPtr << std::endl;
    
    // Move semantics (C++11)
    std::vector<int> vec1 = {1, 2, 3, 4, 5};
    std::vector<int> vec2 = std::move(vec1);  // Move, don't copy
    
    std::cout << "vec1 size after move: " << vec1.size() << std::endl;
    std::cout << "vec2 size: " << vec2.size() << std::endl;
    
    return 0;
}

Performance Optimization

✅ Best Practices

  • • Use const references for large objects
  • • Prefer smart pointers over raw pointers
  • • Use move semantics for expensive operations
  • • Reserve vector capacity when size is known
  • • Use algorithms instead of manual loops
  • • Enable compiler optimizations (-O2, -O3)

❌ Avoid

  • • Unnecessary copying of large objects
  • • Memory leaks with raw pointers
  • • Premature optimization
  • • Using C-style arrays instead of std::array
  • • Ignoring const correctness
  • • Deep inheritance hierarchies