C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
59: Template Metaprogramming Basics
When you first run into template metaprogramming (TMP), it usually feels like you've stumbled into a different language entirely. It looks like C++, but it behaves like a functional language where everything is immutable and recursion is your only tool. Let's clear up the confusion.
Wait, isn't this just generic programming?
Not quite. When you write a std::vector<T>, you're doing generic programming. You're telling the compiler, "I don't care what T is; just make the logic work for any type." That's about code reuse.
Template Metaprogramming is different. It's about computation. With TMP, you're using the compiler as an execution engine to calculate values or generate types before the program even starts running. If a calculation happens during TMP, the result is a constant by the time the CPU ever sees your binary. I've used this in the past to pre-calculate lookup tables for physics engines, which saves precious milliseconds during the game loop because the math is already "done."
How do I actually "calculate" things without a loop?
This is where most people get tripped up. You can't use for or while loops inside a template definition because those are runtime constructs. To "loop" in TMP, we use template recursion and template specialization.
Think of specialization as your "if" statement or your "base case." Here is the classic example: calculating a factorial at compile time.
template<int N> struct Factorial { static constexpr int value = N * Factorial<N - 1>::value; }; // This is the specialization. It stops the recursion. template<> struct Factorial<0> { static constexpr int value = 1; }; // Usage: int main() { // The compiler calculates this. The binary literally just contains the number 120. int result = Factorial<5>::value; }I'll be honest: writing structs for everything is clunky. You're essentially creating a new type for every single step of the calculation. It's a bit of a memory hog for the compiler, but it's incredibly powerful for ensuring correctness before the code even runs.
Do I even need this if I have
constexpr?You're asking the right question. In modern C++ (C++11 and later, especially C++14/17),
constexprfunctions have replaced a huge chunk of old-school TMP. Aconstexprfunction looks like a normal function, but the compiler can evaluate it at compile time if the inputs are known.So why learn the "hard way" with templates? Because
constexpronly handles values. TMP handles types. If you need to conditionally remove aconstqualifier from a type, or if you want to create a tuple of types based on some logic,constexprcan't help you. You need the template engine for that. You'll see this heavily in the<type_traits>library, which is the backbone of almost every professional C++ library today.
📋 Practical Task
Exercise: The Compile-Time Power Calculator
Your goal is to implement a template metaprogram that calculates the power of an integer (base^exp) at compile time. You cannot use the std::pow function, as that is a runtime function.
- Create a template struct called
Powerthat takes two template parameters:int Baseandint Exp. - Implement the recursive step:
Base^Exp = Base * Power<Base, Exp - 1>. - Implement a template specialization for the base case where
Exp == 0(which should return 1). - In your
mainfunction, use astatic_assertto verify thatPower<2, 10>::valueis exactly 1024.
Remember: if the static_assert passes, the code will compile. If you got the math wrong, the compiler will throw an error and refuse to build the program—which is exactly the point of TMP!
There are no comments for now.