We have seen using type template parameters in function templates. There is another kind of template parameters: non-type template parameters that we can use. For example,

template <int D>
void print()
{
    std::cout << D << "\n";
}
 
print<5>();

Here we define the parameter named D of type int. Compiler would create function from this template that looks like:

template <int D>
void print();
 
template <>
void print<5>()
{
    std::cout << 5 << "\n";
}

Why Do We Need Them?

This allows us to imitate passing constexpr values as function parameters that we normally can’t do. This allows us to use those values as contexts that require constant expressions.

For example, std::bitset<SIZE> takes SIZE constexpr to specify number of bits to store. SIZE is non-type template parameter.

Another example we can think of a requirement where we want a template function that takes a value as context that may be internally severing some purpose (used in condition etc.). See below example,

template <char N>
auto withConditionalLog(int value)
{
    if (N == 'y')
    {
        std::cout << "Value " << value << "\n";
    }
    return value;
}
 
withConditionalLog<'y'>(1);
withConditionalLog<'n'>(1);

It will only print value if non-type template parameter value is y. This is very dumb example but I think this should make some sense.

References

  1. https://www.learncpp.com/cpp-tutorial/non-type-template-parameters/