We have seen using type template parameters in function templates. There is another kind of template parameters: non-type template parameters. Non-type template parameters have fixed type (as such int, double etc.) and they are placeholder for constexpr values that would be passed as template argument while invoking the templated function.
For example,
template <int D>
void print()
{
std::cout << D << "\n";
}Here we define the non-type template parameter named D of fixed type int. When we call print<5>();, 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 in constant expression contexts.
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.