可以通过使用不同的模板参数列表来重载函数模板(如果我正确解释https://en.cppreference.com/w/cpp/language/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;
}
对于类模板来说,情况并非如此:
template<typename T> struct F;
//template<uint8_t N> struct F; // interpreted as redeclaration
我的问题有两个:
如果模板参数列表的参数种类或数量不同,则它们不等效,并且很容易实现重载解析。
你是对的,这使得函数模板与众不同,并且允许重载。 然而,函数模板中参数的数量或种类并不能告诉您哪个参数会获胜或参与重载决策。
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);
在大多数情况下,您调用函数模板时无论如何都不会显式提供模板参数,例如
foo(my_pair)
,然后必须从函数参数中推导参数。
具有不同数量或类型的模板参数仅意味着某些重载不会进入重载集,因为推导失败,例如foo<int, float>
只能参考(1),不能参考其他重载。
为什么类模板不可能这样做?
类模板已经具有部分排序机制,以便选择更专业的模板。不过,类模板上的模板参数集始终相同。
同时拥有专门化的部分排序机制和重载机制将创建一个极其复杂的系统;将有两个并行运行的排序机制来确定重载的哪个专门化是最专门化的。
如果类模板仅支持重载,那么它们需要对主模板进行某种推导,例如
template <typename T, std::size_t N> // primary template
struct element_type<std::array<T, N>> { using type = T; };
说实话,事后看来这可能是更好的语言设计。