template<typename T>
void func(T t) {
cout << "func(T t)" << endl;
}
struct X {};
template<> // template specialization of func
void func(const X& x) {
cout << "func( X& x)" << endl;
}
X x ;
const X& y = x;
func(x);
func(y);
Run Code Online (Sandbox Code Playgroud)
始终调用 func(T t)。我不想显式调用 func<const X&>(y) 在这种情况下它会调用第二个函数。
正如您的问题标题所暗示的那样,显式专业化并不是第二个模板。模板的显式特化本身既不是模板也不是模板化实体。
正如您在问题正文中使用“第二个函数”所暗示的那样,它也不是额外的重载。它不参与重载解析或模板参数推导。
它所做的唯一一件事(本质上)就是将原始函数模板的通用函数体替换为一组显式给定的模板参数,在您的情况下,这些模板参数是 的模板参数,这是通过与inT = const X&进行比较而推导出来的,因为您没有' t 显式地为显式专业化提供模板参数(例如 with )。Tconst X&template<> void func(const X& x)template<> void func<const X&>(const X& x)
x作为 中的表达式的类型func(x)是X。y作为 中的表达式的类型func(y)是const X。表达式从来没有引用类型。引用从 id 表达式引用的实体类型中剥离。相反,表达式具有值类别,这些类别在某种程度上对应于引用限定的概念(请参阅 参考资料decltype),但特别是命名变量的 id 表达式始终是左值,而不管变量类型的引用限定如何。
调用的模板参数推导func(/*...*/)始终使用模板本身完成,而不是显式特化。因为模板有一个类型为 的参数T t,T所以永远不会被推导为引用类型。相反,它将T = X推论func(x)和func(y)。const不会根据非引用参数推导参数的顶层。
然而,您明确的专业化是针对T = const X&,而不是T = X。所以不会被使用。
您编写模板和专业化的方式只能通过显式提供模板参数来使用显式专业化,例如
func<const X&>(x);
func<const X&>(y);
Run Code Online (Sandbox Code Playgroud)
如果您希望显式特化也用于推导的模板参数,请使用特化的参数而X x不是const X& x,这将导致函数调用按值传递参数,或者使用函数参数T&、const T&或编写函数模板T&&,以便参数始终被推导为引用,并且调用将通过引用进行。
在后一种情况下您想要哪种确切形式取决于您想要什么行为。例如const T&,在推导之后,参数始终是const- 限定的,因此您的显式专业化将匹配任何X类型参数,而 forT&和T&&如果参数本身不是const- 限定的,则不会匹配。const T&并T&&允许传递右值参数,同时T&不允许传递。
有关参考,请参阅https://en.cppreference.com/w/cpp/language/function_template和https://en.cppreference.com/w/cpp/language/template_argument_deduction和链接页面。不过,作为切入点,这可能信息过于密集,在这种情况下,深入了解此处列出的模板的一本书籍可能会有所帮助。