我已通过VS2010运行以下代码。
#include <iostream>
template<class T> // (a) a base template
void f( T )
{ std::cout << "(a)" << std::endll;}
template<class T> // (b) a second base template, overloads (a)
void f( T* ) // (function templates can't be partially
{ std::cout << "(b)" << std::endll;}
template<> // (c) explicit specialization of (b)
void f<>(int*)
{ std::cout << "(c)" << std::endll;}
int main(int argc, char* argv[])
{
int *p = new int(10);
f( p ); // '(c)'
return 0;
}
/////////////////
#include <iostream>
template<class T> // (a) same old base template as before
void f( T )
{ std::cout << "(a)" << std::endll;}
template<> // (c) explicit specialization, this time of (a)
void f<>(int*)
{ std::cout << "(c)" << std::endll;}
template<class T> // (b) a second base template, overloads (a)
void f( T* )
{ std::cout << "(b)" << std::endll;}
int main(int argc, char* argv[])
{
int *p = new int(10);
f( p ); // '(b)'
return 0;
}
输出结果为(c)
。
但是,如果我在(b)前移动(c)代码块,则输出结果为(b)
。
我在这里阅读了相关文章http://www.gotw.ca/publications/mill17.htm。仍然感到困惑。
为什么代码的顺序在这种情况下很重要?
答案 0 :(得分:2)
我认为你已经在问题中提供了大部分信息。问题是有两个基本模板是重载,否则无关。
如果在仅声明第一个特殊化时执行特化,则编译器会将其视为T == int*
的第一个模板的特化。现在,在声明了两个模板之后,当您执行调用时,编译器将只查看基本模板,并确定第二个模板是表达式的更好匹配。第二个模板没有特化,因此使用了基本模板定义。
让我强调一下:模板专精化只有在选择了基本模板后才能发挥作用。它们不会影响编译器将选择哪个基本模板。
如果在之后将专门化移动到,则声明第二个模板,编译器将该专业化与第二个基本模板T == int
匹配。在这种情况下,当编译器选择第二个模板作为main
中调用的最佳匹配时,专业化将启动,您将获得专门的行为。
答案 1 :(得分:1)
正如文章中所解释的,当您移动专业化时,它会更改哪个功能正在专业化。当您在(b)之前放置专业化时,它专门化(a)。
template<> // (c) explicit specialization of (a) <-- here
void f<>(int*)
{ cout << "(c)" << endl;}
在这两种情况下,当您调用f(p)
时,编译器所做的第一件事就是查看(a)和(b),并确定哪个重载更合适。正如您列出的文章所解释的那样,专业化不参与重载解析,因此在两个示例中,它都选择(b)。此时它会查找(b)的任何特化。
在第一种情况下,由于你有专门的(b)和(c),它执行(c)。在第二种情况下,由于你没有专门(b),它执行(b)。
编辑:防止订单生效的最简单方法是在提供专业化之前转发声明(a)和(b)。在这种情况下,编译器能够推断出您的意图。见http://ideone.com/qj2JC