C++ Template Patterns
Function and Class Templates
// Function template
template<typename T>
T max_val(T a, T b) { return a > b ? a : b; }
// Class template with default
template<typename T, std::size_t N = 8>
class RingBuffer {
std::array<T, N> data_;
std::size_t head_ = 0, size_ = 0;
public:
void push(T val) { data_[head_++ % N] = std::move(val); }
T& front() { return data_[(head_ - size_) % N]; }
};
C++20 Concepts (Preferred over SFINAE)
#include <concepts>
// Define a concept
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
// Constrain a function
template<Numeric T>
T square(T x) { return x * x; }
// Abbreviated function template (C++20)
auto add(Numeric auto a, Numeric auto b) { return a + b; }
// Requires clause for complex constraints
template<typename T>
requires std::copyable<T> && std::equality_comparable<T>
bool contains(const std::vector<T>& v, const T& val) {
return std::ranges::find(v, val) != v.end();
}
SFINAE (Pre-C++20 Compatibility)
#include <type_traits>
// enable_if style
template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
void process(T val) { /* integral version */ }
// C++17 if constexpr (preferred over tag dispatch)
template<typename T>
void serialize(const T& val) {
if constexpr (std::is_arithmetic_v<T>) {
write_numeric(val);
} else if constexpr (std::is_same_v<T, std::string>) {
write_string(val);
} else {
val.serialize(*this); // assumes serialize() method
}
}
Variadic Templates
// Parameter pack expansion
template<typename... Args>
void log(const char* fmt, Args&&... args) {
std::printf(fmt, std::forward<Args>(args)...);
}
// Fold expressions (C++17)
template<typename... T>
auto sum(T... vals) { return (vals + ...); } // unary right fold
auto product(T... vals) { return (1 * ... * vals); } // binary left fold
template<typename... Ts>
void print_all(Ts&&... args) {
((std::cout << args << ' '), ...); // comma fold
}
Type Traits and Metaprogramming
// Conditional type
using IntOrFloat = std::conditional_t<sizeof(long) == 8, long, long long>;
// Type list operations
template<typename... Ts>
struct TypeList {};
template<typename TL>
struct Head;
template<typename T, typename... Ts>
struct Head<TypeList<T, Ts...>> { using type = T; };
// Detecting member existence (C++20 requires)
template<typename T>
concept HasSize = requires(T t) { { t.size() } -> std::convertible_to<std::size_t>; };
Template Specialization
// Primary template
template<typename T>
struct Serializer { static std::string to_json(const T& v); };
// Full specialization
template<>
struct Serializer<bool> {
static std::string to_json(bool v) { return v ? "true" : "false"; }
};
// Partial specialization
template<typename T>
struct Serializer<std::vector<T>> {
static std::string to_json(const std::vector<T>& v) {
std::string result = "[";
for (const auto& e : v) result += Serializer<T>::to_json(e) + ",";
if (result.back() == ',') result.pop_back();
return result + "]";
}
};