Function-templates can be overloaded by using different template-parameter-lists (if I interpret https://en.cppreference.com/w/cpp/language/function_template correctly). If the template-parameter-lists are different in parameter kinds or number, they are not equivalent and overload-resolution is easily possible.
So, the following are three overloads of function template foo()
:
template<typename T>
auto foo(int v) {
return 1 * v;
}
template<typename T, typename U>
auto foo(int v) {
return 3 * v;
}
template<uint8_t N>
auto foo(int v) {
return 2 * v;
}
This is not true for class-templates like:
template<typename T> struct F;
//template<uint8_t N> struct F; // interpreted as redeclaration
My question is two-fold:
If the template-parameter-lists are different in parameter kinds or number, they are not equivalent and overload-resolution is easily possible.
You are right that this makes the function templates distinct, and allows for overloading. However, the amount or kinds of parameters in a function template doesn't tell you which one would win or participate in overload resolution.
template <typename T, typename U> // (1)
void foo(std::pair<T, U>);
template <typename T> // has fewer template parameters than (1), but is more specialized
void foo(std::pair<T, int>);
template <typename T> // has fewer template parameters than (1), but is less specialized
void foo(T);
In most cases, you call function templates without explicitly providing template arguments anyway, such as foo(my_pair)
, and then the parameters will have to be deduced from the function argument.
Having a different amount or kind of template parameters only means that some overloads don't enter the overload set because deduction fails, e.g. foo<int, float>
can only refer to (1), not to the other overloads.
why is that not possible for class-templates?
Class templates already have a partial ordering mechanism in order to select the more specialized ones. The set of template parameters on the class template is always the same though.
Having both a partial ordering mechanism for specializations and an overloading mechanism would create an immensely complex system; there would be two ordering mechanism running in parallel to determine which specialization of an overload is most specialized.
If class templates only supported overloading, then they would need some kind of deduction on the primary template, e.g.
template <typename T, std::size_t N> // primary template
struct element_type<std::array<T, N>> { using type = T; };
To be honest, this may have been better language design in hindsight.