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 longSFINAE
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);
}