C++TemplatesSTLGeneric ProgrammingTemplate MetaprogrammingContainersAlgorithmsIteratorsInteractive VisualizationCore Concept
Templates & STL in C++
Master C++ templates and the Standard Template Library. Learn generic programming, template metaprogramming, and STL containers and algorithms.
Best viewed on desktop for optimal interactive experience
Templates & STL: Generic Programming in C++
Templates are C++'s mechanism for generic programming, allowing you to write code that works with different types. The Standard Template Library (STL) is built on templates and provides a rich collection of containers, algorithms, and utilities.
Template Types
- Function Templates: Generic functions
- Class Templates: Generic classes
- Variable Templates: Generic variables (C++14)
- Alias Templates: Generic type aliases
Templates & STL Overview
Template Types
- Function Templates: Generic functions
- Class Templates: Generic classes
- Variable Templates: Generic variables (C++14)
- Alias Templates: Generic type aliases
STL Components
- Containers: Data structures (vector, map, etc.)
- Algorithms: Functions (sort, find, etc.)
- Iterators: Pointer-like objects
- Function Objects: Callable objects
Interactive Template & STL Explorer
// Basic function template
template<typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
// Usage with different types
int i = max(10, 20); // T = int
double d = max(3.14, 2.71); // T = double
std::string s = max(std::string("hello"), std::string("world"));
// Template argument deduction
template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) { // C++11
return a + b;
}
// C++14 and later - even simpler
template<typename T, typename U>
auto multiply(T a, U b) {
return a * b;
}
// Template specialization
template<typename T>
void print(T value) {
std::cout << value << std::endl;
}
// Specialization for strings
template<>
void print<std::string>(std::string value) {
std::cout << "String: " << value << std::endl;
}
Template argument deduction allows the compiler to automatically determine template parameters from function arguments.
Best Practices & Performance Tips
Template Design
- • Use meaningful template parameter names
- • Provide default template arguments when sensible
- • Consider template argument deduction
- • Use SFINAE or concepts for constraints
- • Separate interface from implementation
STL Usage
- • Prefer STL algorithms over hand-written loops
- • Choose appropriate container for your use case
- • Use iterators for generic code
- • Reserve capacity for vectors when size is known
- • Use emplace operations instead of insert
Function Templates
Basic Syntax
template<typename T> T max(T a, T b) { return (a > b) ? a : b; } // Usage int i = max(10, 20); // T = int double d = max(3.14, 2.71); // T = double
Template Argument Deduction
template<typename T, typename U> auto add(T a, U b) -> decltype(a + b) { return a + b; } // C++14 and later template<typename T, typename U> auto add(T a, U b) { return a + b; }
Specialization
// Primary template template<typename T> void print(T value) { std::cout << value << std::endl; } // Specialization for strings template<> void print<std::string>(std::string value) { std::cout << "String: " << value << std::endl; }
Class Templates
Basic Class Template
template<typename T> class Stack { private: std::vector<T> data; public: void push(const T& item) { data.push_back(item); } T pop() { if (empty()) { throw std::runtime_error("Stack is empty"); } T item = data.back(); data.pop_back(); return item; } bool empty() const { return data.empty(); } size_t size() const { return data.size(); } }; // Usage Stack<int> intStack; Stack<std::string> stringStack;
Template Parameters
template< typename T, // Type parameter size_t N = 10, // Non-type parameter with default typename Allocator = std::allocator<T> // Type parameter with default > class FixedArray { T data[N]; // ... };
STL Components
Containers
- Sequence Containers: vector, deque, list, array, forward_list
- Associative Containers: set, map, multiset, multimap
- Unordered Containers: unordered_set, unordered_map, etc.
- Container Adaptors: stack, queue, priority_queue
Container Examples
// Vector - dynamic array std::vector<int> vec{1, 2, 3, 4, 5}; // Map - key-value pairs std::map<std::string, int> wordCount; wordCount["hello"] = 5; // Set - unique elements std::set<int> uniqueNumbers{3, 1, 4, 1, 5, 9}; // {1, 3, 4, 5, 9} // Unordered map - hash table std::unordered_map<std::string, double> prices; prices["apple"] = 1.50;
Iterators
Iterator Categories
- Input Iterator: Read-only, single-pass
- Output Iterator: Write-only, single-pass
- Forward Iterator: Read/write, multi-pass
- Bidirectional Iterator: Forward + backward
- Random Access Iterator: Bidirectional + jump
Iterator Usage
std::vector<int> vec{1, 2, 3, 4, 5}; // Iterator-based loop for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } // Range-based for (C++11+) for (const auto& value : vec) { std::cout << value << " "; } // Iterator arithmetic auto it = vec.begin(); std::advance(it, 2); // Move iterator 2 positions auto distance = std::distance(vec.begin(), vec.end());
STL Algorithms
Algorithm Categories
- Non-modifying: find, count, search
- Modifying: copy, transform, replace
- Sorting: sort, partial_sort, nth_element
- Binary Search: lower_bound, upper_bound, binary_search
- Set Operations: set_union, set_intersection
Algorithm Examples
std::vector<int> vec{3, 1, 4, 1, 5, 9, 2, 6, 5}; // Sorting std::sort(vec.begin(), vec.end()); // Finding elements auto it = std::find(vec.begin(), vec.end(), 5); if (it != vec.end()) { std::cout << "Found 5 at position " << std::distance(vec.begin(), it); } // Transforming elements std::vector<int> squares(vec.size()); std::transform(vec.begin(), vec.end(), squares.begin(), [](int x) { return x * x; }); // Filtering std::vector<int> evens; std::copy_if(vec.begin(), vec.end(), std::back_inserter(evens), [](int x) { return x % 2 == 0; }); // Reducing int sum = std::accumulate(vec.begin(), vec.end(), 0);
Template Metaprogramming
SFINAE (Substitution Failure Is Not An Error)
#include <type_traits> // Enable if T is integral template<typename T> typename std::enable_if<std::is_integral<T>::value, T>::type processValue(T value) { return value * 2; } // Enable if T is floating point template<typename T> typename std::enable_if<std::is_floating_point<T>::value, T>::type processValue(T value) { return value * 3.14; }
Modern Approach with Concepts (C++20)
#include <concepts> template<std::integral T> T processValue(T value) { return value * 2; } template<std::floating_point T> T processValue(T value) { return value * 3.14; }
Type Traits
Standard Type Traits
#include <type_traits> template<typename T> void analyzeType() { if constexpr (std::is_integral_v<T>) { std::cout << "T is an integral type\n"; } if constexpr (std::is_pointer_v<T>) { std::cout << "T is a pointer type\n"; } if constexpr (std::is_const_v<T>) { std::cout << "T is const\n"; } }
Custom Type Traits
// Check if a type has a specific member function template<typename T, typename = void> struct has_size : std::false_type {}; template<typename T> struct has_size<T, std::void_t<decltype(std::declval<T>().size())>> : std::true_type {}; template<typename T> constexpr bool has_size_v = has_size<T>::value;
Perfect Forwarding
Universal References and Forwarding
template<typename T> void wrapper(T&& arg) { // Perfect forwarding preserves value category actualFunction(std::forward<T>(arg)); } // Variadic template with perfect forwarding template<typename F, typename... Args> auto call_function(F&& f, Args&&... args) -> decltype(f(std::forward<Args>(args)...)) { return f(std::forward<Args>(args)...); }
Best Practices
Template Design
- Use meaningful template parameter names
- Provide default template arguments when sensible
- Consider template argument deduction
- Use SFINAE or concepts for constraints
- Separate interface from implementation
STL Usage
- Prefer STL algorithms over hand-written loops
- Choose appropriate container for your use case
- Use iterators for generic code
- Take advantage of range-based for loops
- Understand iterator invalidation rules
Performance Tips
- Reserve capacity for vectors when size is known
- Use emplace operations instead of insert
- Prefer algorithms that work in-place
- Choose unordered containers for hash-based lookups
- Use move semantics with containers
Modern C++ Enhancements
C++11
- Range-based for loops
- Auto type deduction
- Variadic templates
- Move semantics in containers
C++14
- Generic lambdas
- Variable templates
- Make functions for containers
C++17
- Structured bindings
- Parallel algorithms
- std::optional and std::variant
C++20
- Concepts
- Ranges library
- Coroutines
Templates and STL form the backbone of modern C++ programming, enabling efficient, generic, and reusable code.