Just as you can write function templates, you can write class templates to create generic data structures. We can also pass actual values (like integers or pointers) as template arguments. These are called non type template parameters.
Let's look at class templates and how value parameters enable compile time collection sizes.
Class Templates: Generic Containers
A class template allows you to define a structure where the type of member variables is determined at compile time. This is how containers like vectors and lists are built. Let's look at a custom wrapper class:
Non Type Template Parameters: Compile Time Values
What if you want to specify the size of an array at compile time using templates? You can pass values (like integers) directly inside the angle brackets. The syntax is:
Because Size is a template parameter, the compiler instantiates a completely unique class type for each size. For example, StaticArray<int, 5> and StaticArray<int, 10> are treated as two entirely different, incompatible classes. You cannot assign one to the other.
The std::array Collection
The standard library provides std::array as a safer, zero cost wrapper around raw arrays. It uses non type template parameters to reserve space directly on the stack, preventing dynamic heap allocation latency:
* The Sizing Metaphor: Non type template parameters are like baking templates. Instead of buying a baking tray that can resize itself at runtime (like a slow dynamic vector), you buy a rigid 8 inch steel tray (a stack allocated template array). It is incredibly sturdy and requires zero assembly, but you cannot change its size once it is placed in the oven.
Class Template Argument Deduction (CTAD)
In older C++ versions, you had to explicitly write all type parameters when instantiating a class template (e.g. Wrapper<int> w{5}). Since C++17, the compiler can automatically deduce the template parameters from the arguments passed to the constructor. This is called Class Template Argument Deduction (CTAD):