Template Metaprogramming

Compile-time computation with C++ templates

Type Traits

Query and transform types at compile time using the type_traits library.

#include <type_traits>

// Query type properties
static_assert(std::is_integral_v<int>);        // true
static_assert(std::is_floating_point_v<double>); // true
static_assert(std::is_pointer_v<int*>);         // true
static_assert(std::is_reference_v<int&>);       // true

// Transform types
using T1 = std::remove_reference_t<int&>;      // int
using T2 = std::add_pointer_t<int>;            // int*
using T3 = std::make_unsigned_t<int>;          // unsigned int
using T4 = std::decay_t<int&&>;                // int

// Conditional types
template<typename T>
using promote_t = std::conditional_t<
    sizeof(T) < sizeof(int),
    int,
    T
>;

// Usage: promote_t<short> is int
//        promote_t<long> is long

SFINAE

Substitution Failure Is Not An Error - enable/disable templates based on type properties.

// Enable only for integral types
template<typename T>
std::enable_if_t<std::is_integral_v<T>, T>
square(T value) {
    return value * value;
}

// Enable only for floating point
template<typename T>
std::enable_if_t<std::is_floating_point_v<T>, T>
square(T value) {
    return value * value;
}

// C++20 Concepts (replaces SFINAE)
template<std::integral T>
T square(T value) { return value * value; }

template<std::floating_point T>
T square(T value) { return value * value; }

Variadic Templates

// Recursive unpacking
template<typename T>
void print(T value) {
    std::cout << value << std::endl;
}

template<typename T, typename... Rest>
void print(T first, Rest... rest) {
    std::cout << first << " ";
    print(rest...);
}

// C++17 fold expression
template<typename... Args>
void print(Args... args) {
    ((std::cout << args << " "), ...);
    std::cout << std::endl;
}

// Type list operations
template<typename... Types>
struct TypeList {
    static constexpr size_t size = sizeof...(Types);
};

using MyTypes = TypeList<int, double, char>;
static_assert(MyTypes::size == 3);

Compile-time Computation

// Factorial at compile time (C++11/14)
template<int N>
struct Factorial {
    static constexpr int value = N * Factorial<N - 1>::value;
};

template<>
struct Factorial<0> {
    static constexpr int value = 1;
};

static_assert(Factorial<5>::value == 120);

// C++17 constexpr function (simpler!)
constexpr int factorial(int n) {
    int result = 1;
    for (int i = 2; i <= n; ++i) {
        result *= i;
    }
    return result;
}

static_assert(factorial(5) == 120);

// C++20 consteval (must evaluate at compile time)
consteval int ct_factorial(int n) {
    return n <= 1 ? 1 : n * ct_factorial(n - 1);
}