I have read many questions and answers, but this question caught my eye the most; it and its answers are helpful but I still feel that I do not fully understand the uses and the theories behind using non-type template arguments. They provide many useful examples as to when it is used, but none really shed light on the theories behind the non-type template arguments.
I am interested in knowing not specifically when in examples, but more broadly why I would be inclined to use a non-type template argument over just a regular function argument.
I understand that they are determined at compile-time and that every new call creates a new function with the determined value for the non-type template argument. So why exactly would I want to create many different instances of the same function when I could just input the parameter I want into a function and have the same result - supposedly - with only one compiled function.
In essence, why should I be inclined to do #1, instead of #2, as according to the final section of this page of cplusplus.com?
#1:
template <class T, int N>
T fixed_multiply (T val)
{
return val * N;
}
int main() {
std::cout << fixed_multiply<int,2>(10) << '\n';
std::cout << fixed_multiply<int,3>(10) << '\n';
}
#2:
template <class T>
T fixed_multiply (T val, int N)
{
return val * N;
}
int main() {
std::cout << fixed_multiply<int>(10, 2) << '\n';
std::cout << fixed_multiply<int>(10, 3) << '\n';
}
In addition, would there be any performance benefits or the such of either one? Are there any common applications that could benefit from using non-type template arguments, or is this a highly technical parameter used in specific applications to yield specific results?
Edit: This got marked as a duplicate for some reason, the first paragraph explains my reasons for a similar question.
std::transform
– Murpheyconstexpr
function that is evaluated at compile time. Non-type template arguments are also useful for things likestd::array
or functions taking C-style arrays to get an actual array type with size, and not needing to pass the size as a run-time argument. – Avantgardestd::bind
. – Avantgardestd::bind
, which is worse. By that logic, type templates are not needed, because you can just use a bunch of overloads. The problem with OP question is that both approaches are viable. One might be preferred over other depending on intended usage. – Murphey2
can generate a left shift instead of a multiply, and the calling sequence only has to pass one parameter. – Exudeintegral_constant
and similar constructions could solve it. – Datnow