在this article中,他们说(c)明确专门化(b)。我怀疑为什么我们不能说这是(a)的明确专业化?因为我们可以为任何特定类型专门化模板。所以在专注于int *时,为什么他们会说(c)(b)的明确专业化。
template<class T> // (a) a base template
void f( T );
template<class T> // (b) a second base template, overloads (a)
void f( T* ); // (function templates can't be partially
// specialized; they overload instead)
template<> // (c) explicit specialization of (b)
void f<>(int*);
任何评论都有助于理解这些事情。
答案 0 :(得分:3)
如果(b)不存在,则(c)确实是(a)的有效专业化。实际上,只是改变源代码行的顺序,以便(c)在编译器看到(b)之前出现,将使它成为(a)的特化!
请考虑以下代码:
int main()
{
int a;
f(&a);
return 0;
}
现在把自己放在编译器的鞋子里。您需要找到具有f
参数的匹配函数int*
。你做什么的?
f
的非模板函数,并查看是否有任何与参数类型相匹配的函数(在本例中为int*
)。f<T>
和f<T*>
。请注意,与类不同,函数模板不能部分专门化,因此就编译器而言,这些是完全独立的重载。f<T*>
基本模板更匹配,因此您可以使用T=int
对其进行实例化。现在,如果您已经看过f<int*>
的专业化,那么您可以使用它,否则您将生成该函数。现在这是有趣的事情。如果我们更改原始代码的顺序,则
template<class T> void f( T ); // (i)
template<> void f<>(int*); // (ii)
template<class T> void f( T* ); // (iii)
然后编译器现在看到(ii)作为(i)的特化 - 因为它按顺序处理事物,并且在达到(ii)时它不知道(iii)存在了!但由于它仅匹配基本模板,因此它决定(iii)是比(i)更好的匹配 - 现在(iii)没有任何特化,因此您获得默认实例化。
这一切都让人很困惑,有时甚至会让最有经验的C ++程序员绊倒。所以基本规则是:不专门化函数模板,而是使用正常函数重载。一个普通的旧模板
void f(int*);
之前会匹配,并避免这一切。
编辑:。请求在评论中引用标准。我担心我只能提供C ++ 03版本,但这里有:
第4.7.3.3段:“明确专门化的函数模板或类模板的声明应在声明明确专门化的范围内。”。
这就是为什么在上面的例子中,(ii)不能被视为(iii)的明确专业化,因为(iii)尚未在范围内。
第4.8.3节:“当写入对[函数]名称的调用时...模板参数推导(14.8.2)和任何显式模板参数(14.3)的检查都是针对执行的每个函数模板,以查找可与该函数模板一起使用的模板参数值(如果有),以实例化可使用调用参数调用的函数模板特化。“
换句话说,(正如我所读到的,无论如何)它始终会查看每个基本模板,无论如何 - 提供明确的专业化没有任何区别。
同一段落继续:“对于每个函数模板,如果参数推断和检查成功,则使用模板参数(推导和/或显式)来实例化添加到的单个函数模板特化。候选函数设置为在重载决策中使用。“
因此,只有在这一点(我读到它)才会考虑明确的专业化。
最后,也许最重要的是在这种情况下,第13.3.3节涉及选择过载集中的“最佳可行功能”。两个项目是相关的:
F1优于F2,如果:“F1和F2是功能模板专精,F1的功能模板比F2的模板更专业,根据14.5.5.2中描述的偏序规则“。这就是f<T*>
版本在尝试匹配f<T>
时在f(int*)
版本之前被选中的原因 - 因为它是一个“更专业”的模板
F1优于F2,如果:“F1是非模板功能而F2是功能模板专业化”,这是我在原版结尾处的建议的基础答案。
呼!