# Template Metaprogramming ## Variadic Templates ```cpp #include #include // Fold expressions (C++17) template auto sum(Args... args) { return (args + ...); // Unary right fold } template void print(Args&&... args) { ((std::cout << args << ' '), ...); // Binary left fold std::cout << '\n'; } // Recursive variadic template template void log(T&& value) { std::cout << value << '\n'; } template void log(T&& first, Args&&... rest) { std::cout << first << ", "; log(std::forward(rest)...); } // Parameter pack expansion template struct TypeList { static constexpr size_t size = sizeof...(Types); }; template auto make_tuple_advanced(Args&&... args) { return std::tuple...>(std::forward(args)...); } ``` ## SFINAE and if constexpr ```cpp #include // SFINAE with std::enable_if (older style) template std::enable_if_t, T> double_value(T value) { return value * 2; } template std::enable_if_t, T> double_value(T value) { return value * 2.0; } // Modern: if constexpr (C++17) template auto process(T value) { if constexpr (std::is_integral_v) { return value * 2; } else if constexpr (std::is_floating_point_v) { return value * 2.0; } else { return value; } } // Detection idiom template struct has_serialize : std::false_type {}; template struct has_serialize().serialize())>> : std::true_type {}; template constexpr bool has_serialize_v = has_serialize::value; // Use with if constexpr template void save(const T& obj) { if constexpr (has_serialize_v) { obj.serialize(); } else { // Default serialization } } ``` ## Type Traits ```cpp #include // Custom type traits template struct remove_all_pointers { using type = T; }; template struct remove_all_pointers { using type = typename remove_all_pointers::type; }; template using remove_all_pointers_t = typename remove_all_pointers::type; // Conditional types template struct conditional_type { using type = T; }; template struct conditional_type { using type = F; }; // Compile-time type selection template struct best_integral_type { using type = std::conditional_t>>; }; // Check for member functions template struct has_reserve : std::false_type {}; template struct has_reserve().reserve(size_t{}))>> : std::true_type {}; ``` ## CRTP (Curiously Recurring Template Pattern) ```cpp // Static polymorphism with CRTP template class Shape { public: double area() const { return static_cast(this)->area_impl(); } void draw() const { static_cast(this)->draw_impl(); } }; class Circle : public Shape { double radius_; public: Circle(double r) : radius_(r) {} double area_impl() const { return 3.14159 * radius_ * radius_; } void draw_impl() const { std::cout << "Drawing circle\n"; } }; class Rectangle : public Shape { double width_, height_; public: Rectangle(double w, double h) : width_(w), height_(h) {} double area_impl() const { return width_ * height_; } void draw_impl() const { std::cout << "Drawing rectangle\n"; } }; // CRTP for mixin capabilities template class Printable { public: void print() const { std::cout << static_cast(this)->to_string() << '\n'; } }; class User : public Printable { std::string name_; public: User(std::string name) : name_(std::move(name)) {} std::string to_string() const { return "User: " + name_; } }; ``` ## Template Template Parameters ```cpp #include #include #include // Template template parameter template class Container> class Stack { Container> data_; public: void push(const T& value) { data_.push_back(value); } T pop() { T value = data_.back(); data_.pop_back(); return value; } size_t size() const { return data_.size(); } }; // Usage with different containers Stack vector_stack; Stack deque_stack; Stack list_stack; ``` ## Compile-Time Computation ```cpp #include // Compile-time factorial constexpr int factorial(int n) { return n <= 1 ? 1 : n * factorial(n - 1); } constexpr int fact_5 = factorial(5); // Computed at compile time // Compile-time prime checking constexpr bool is_prime(int n) { if (n < 2) return false; for (int i = 2; i * i <= n; ++i) { if (n % i == 0) return false; } return true; } // Generate compile-time array of primes template constexpr auto generate_primes() { std::array primes{}; int count = 0; int candidate = 2; while (count < N) { if (is_prime(candidate)) { primes[count++] = candidate; } ++candidate; } return primes; } constexpr auto first_10_primes = generate_primes<10>(); ``` ## Expression Templates ```cpp // Lazy evaluation with expression templates template class VecExpression { public: double operator[](size_t i) const { return static_cast(*this)[i]; } size_t size() const { return static_cast(*this).size(); } }; class Vec : public VecExpression { std::vector data_; public: Vec(size_t n) : data_(n) {} double operator[](size_t i) const { return data_[i]; } double& operator[](size_t i) { return data_[i]; } size_t size() const { return data_.size(); } // Evaluate expression template template Vec& operator=(const VecExpression& expr) { for (size_t i = 0; i < size(); ++i) { data_[i] = expr[i]; } return *this; } }; // Binary operation expression template class VecSum : public VecExpression> { const E1& lhs_; const E2& rhs_; public: VecSum(const E1& lhs, const E2& rhs) : lhs_(lhs), rhs_(rhs) {} double operator[](size_t i) const { return lhs_[i] + rhs_[i]; } size_t size() const { return lhs_.size(); } }; // Operator overload template VecSum operator+(const VecExpression& lhs, const VecExpression& rhs) { return VecSum(static_cast(lhs), static_cast(rhs)); } // Usage: a = b + c + d (no temporaries created!) ``` ## Quick Reference | Technique | Use Case | Performance | |-----------|----------|-------------| | Variadic Templates | Variable arguments | Zero overhead | | SFINAE | Conditional compilation | Compile-time | | if constexpr | Type-based branching | Zero overhead | | CRTP | Static polymorphism | No vtable cost | | Expression Templates | Lazy evaluation | Eliminates temps | | Type Traits | Type introspection | Compile-time | | Fold Expressions | Parameter pack ops | Optimal | | Template Specialization | Type-specific impl | Zero overhead |