Templates Skill
Production-Grade Development Skill | C++ Template Metaprogramming
Master C++ template programming from basics to advanced metaprogramming techniques.
Template Basics
Function Templates
template<typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) {
return a + b;
}
auto multiply(auto a, auto b) {
return a * b;
}
template<typename T, std::size_t N>
constexpr std::size_t array_size(T (&)[N]) {
return N;
}
max(1, 2);
max(1.0, 2.0);
max<double>(1, 2);
Class Templates
template<typename T, std::size_t Capacity = 64>
class FixedVector {
std::array<T, Capacity> data_;
std::size_t size_ = 0;
public:
void push_back(const T& value) {
if (size_ < Capacity) {
data_[size_++] = value;
}
}
T& operator[](std::size_t idx) { return data_[idx]; }
const T& operator[](std::size_t idx) const { return data_[idx]; }
std::size_t size() const { return size_; }
static constexpr std::size_t capacity() { return Capacity; }
};
FixedVector vec{1, 2, 3};
template<typename T, typename... Args>
FixedVector(T, Args...) -> FixedVector<T, 1 + sizeof...(Args)>;
Template Specialization
template<typename T>
struct TypeInfo {
static constexpr const char* name = "unknown";
};
template<>
struct TypeInfo<int> {
static constexpr const char* name = "int";
};
template<>
struct TypeInfo<double> {
static constexpr const char* name = "double";
};
template<typename T>
struct TypeInfo<std::vector<T>> {
static constexpr const char* name = "vector";
using element_type = T;
};
template<typename T>
struct TypeInfo<T*> {
static constexpr const char* name = "pointer";
using pointed_type = T;
};
Variadic Templates
Parameter Packs
template<typename... Args>
void print(Args... args) {
((std::cout << args << ' '), ...);
std::cout << '\n';
}
template<typename... Args>
constexpr std::size_t count_args() {
return sizeof...(Args);
}
template<typename T>
void print_recursive(T t) {
std::cout << t << '\n';
}
template<typename T, typename... Rest>
void print_recursive(T first, Rest... rest) {
std::cout << first << ' ';
print_recursive(rest...);
}
Fold Expressions (C++17)
template<typename... Args>
auto sum(Args... args) {
return (args + ...);
}
template<typename... Args>
auto sum_left(Args... args) {
return (... + args);
}
template<typename... Args>
auto sum_with_init(Args... args) {
return (0 + ... + args);
}
template<typename... Args>
bool all(Args... args) {
return (... && args);
}
template<typename... Args>
bool any(Args... args) {
return (... || args);
}
template<typename F, typename... Args>
void for_each_arg(F f, Args&&... args) {
((std::forward<Args>(args)), ...);
}
SFINAE and enable_if
SFINAE Basics
#include <type_traits>
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
safe_divide(T a, T b) {
return b != 0 ? a / b : 0;
}
template<typename T>
std::enable_if_t<std::is_floating_point_v<T>, T>
safe_divide(T a, T b) {
return b != T{0} ? a / b : std::numeric_limits<T>::quiet_NaN();
}
template<typename, 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 {};
static_assert(has_size<std::vector<int>>::value);
static_assert(!has_size<int>::value);
Detection Idiom
template<typename, template<typename...> class, typename...>
struct is_detected_impl : std::false_type {};
template<template<typename...> class Op, typename... Args>
struct is_detected_impl<std::void_t<Op<Args...>>, Op, Args...>
: std::true_type {};
template<template<typename...> class Op, typename... Args>
using is_detected = is_detected_impl<void, Op, Args...>;
template<typename T>
using has_begin_t = decltype(std::declval<T>().begin());
template<typename T>
using has_end_t = decltype(std::declval<T>().end());
template<typename T>
constexpr bool is_container_v =
is_detected<has_begin_t, T>::value &&
is_detected<has_end_t, T>::value;
Concepts (C++20)
Standard Concepts
#include <concepts>
template<std::integral T>
T gcd(T a, T b) {
while (b != 0) {
T t = b;
b = a % b;
a = t;
}
return a;
}
template<std::floating_point T>
T sqrt_approx(T x);
template<std::copyable T>
void process(T value);
template<std::invocable<int> F>
void apply(F&& func);
template<std::ranges::range R>
void iterate(R&& range);
Custom Concepts
template<typename T>
concept Hashable = requires(T a) {
{ std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};
template<typename T>
concept Printable = requires(std::ostream& os, T value) {
{ os << value } -> std::same_as<std::ostream&>;
};
template<typename T>
concept Container = requires(T c) {
typename T::value_type;
typename T::iterator;
{ c.begin() } -> std::same_as<typename T::iterator>;
{ c.end() } -> std::same_as<typename T::iterator>;
{ c.size() } -> std::convertible_to<std::size_t>;
};
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
template<Container C>
void process(const C& container) {
for (const auto& item : container) {
}
}
void print_hashable(Hashable auto const& value) {
std::cout << std::hash<std::decay_t<decltype(value)>>{}(value);
}
Requires Clauses
template<typename T>
requires std::is_arithmetic_v<T>
T average(std::span<const T> values) {
return std::reduce(values.begin(), values.end()) / values.size();
}
template<typename T>
T* find(T* first, T* last, const T& value)
requires std::equality_comparable<T>
{
while (first != last && *first != value) {
++first;
}
return first;
}
template<typename T>
void process(T val) requires std::integral<T> {
std::cout << "integral\n";
}
template<typename T>
void process(T val) requires std::signed_integral<T> {
std::cout << "signed integral\n";
}
Type Traits
Standard Type Traits
#include <type_traits>
static_assert(std::is_integral_v<int>);
static_assert(std::is_floating_point_v<double>);
static_assert(std::is_class_v<std::string>);
static_assert(std::is_pointer_v<int*>);
static_assert(std::is_const_v<const int>);
static_assert(std::is_trivially_copyable_v<int>);
static_assert(std::is_default_constructible_v<std::string>);
using NoConst = std::remove_const_t<const int>;
using Pointer = std::add_pointer_t<int>;
using Decayed = std::decay_t<int&>;
using Common = std::common_type_t<int, double>;
template<typename T>
using storage_type = std::conditional_t<
sizeof(T) <= sizeof(void*),
T,
std::unique_ptr<T>
>;
Custom Type Traits
template<typename T>
struct is_smart_pointer : std::false_type {};
template<typename T>
struct is_smart_pointer<std::unique_ptr<T>> : std::true_type {};
template<typename T>
struct is_smart_pointer<std::shared_ptr<T>> : std::true_type {};
template<typename T>
constexpr bool is_smart_pointer_v = is_smart_pointer<T>::value;
template<typename T>
struct remove_all_pointers {
using type = T;
};
template<typename T>
struct remove_all_pointers<T*> {
using type = typename remove_all_pointers<T>::type;
};
template<typename T>
using remove_all_pointers_t = typename remove_all_pointers<T>::type;
static_assert(std::is_same_v<remove_all_pointers_t<int***>, int>);
Compile-Time Computation
constexpr Functions
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
static_assert(factorial(5) == 120);
class ConstexprString {
const char* data_;
std::size_t size_;
public:
constexpr ConstexprString(const char* str)
: data_(str), size_(0) {
while (str[size_] != '\0') ++size_;
}
constexpr std::size_t size() const { return size_; }
constexpr char operator[](std::size_t i) const { return data_[i]; }
};
constexpr auto hello = ConstexprString("Hello");
static_assert(hello.size() == 5);
consteval (C++20)
consteval int square(int n) {
return n * n;
}
constexpr int x = square(5);
consteval std::size_t hash_string(std::string_view str) {
std::size_t hash = 0;
for (char c : str) {
hash = hash * 31 + static_cast<std::size_t>(c);
}
return hash;
}
switch (hash_string(input)) {
case hash_string("foo"): /* ... */ break;
case hash_string("bar"): /* ... */ break;
}
Template Error Messages
Better Error Messages with Concepts
template<typename T>
void sort_container(T& container) {
std::sort(container.begin(), container.end());
}
template<typename T>
concept Sortable = requires(T c) {
{ c.begin() } -> std::random_access_iterator;
{ c.end() } -> std::random_access_iterator;
};
template<Sortable T>
void sort_container(T& container) {
std::sort(container.begin(), container.end());
}
Static Assert for Custom Messages
template<typename T>
class NumericContainer {
static_assert(std::is_arithmetic_v<T>,
"NumericContainer requires an arithmetic type (int, float, etc.)");
};
Troubleshooting Decision Tree
Template error?
├── "no matching function"
│ ├── Check template parameter deduction
│ ├── Check SFINAE conditions
│ └── Add explicit template arguments
├── "ambiguous call"
│ ├── Make one overload more specific
│ ├── Use concepts for disambiguation
│ └── Add explicit template arguments
├── "incomplete type"
│ ├── Forward declare issue
│ ├── Move implementation to .cpp (explicit instantiation)
│ └── Check circular dependencies
├── "exceeds maximum depth"
│ ├── Add base case to recursion
│ ├── Increase compiler limit
│ └── Use fold expressions instead
└── "constraint not satisfied"
├── Check concept requirements
└── Add missing operations to type
Unit Test Template
#include <gtest/gtest.h>
#include <type_traits>
class TemplateTest : public ::testing::Test {};
TEST_F(TemplateTest, TypeTraitsWork) {
static_assert(std::is_integral_v<int>);
static_assert(!std::is_integral_v<double>);
static_assert(is_smart_pointer_v<std::unique_ptr<int>>);
}
TEST_F(TemplateTest, ConceptsSatisfied) {
static_assert(Hashable<int>);
static_assert(Hashable<std::string>);
static_assert(Container<std::vector<int>>);
static_assert(!Container<int>);
}
TEST_F(TemplateTest, VariadicSum) {
EXPECT_EQ(sum(1, 2, 3, 4, 5), 15);
EXPECT_DOUBLE_EQ(sum(1.0, 2.5, 3.5), 7.0);
}
TEST_F(TemplateTest, ConstexprComputation) {
constexpr auto result = factorial(5);
EXPECT_EQ(result, 120);
hash = ();
(hash, );
}
(TemplateTest, Specialization) {
(TypeInfo<>::name, );
(TypeInfo<>::name, );
(TypeInfo<std::vector<>>::name, );
}
Integration Points
| Component | Interface |
|---|
stl-master | Generic containers |
modern-cpp-expert | Concepts, constexpr |
performance-optimizer | Compile-time optimization |
cpp-algorithms-agent | Generic algorithms |
C++ Plugin v3.0.0 - Production-Grade Development Skill