template <typename T,typename U> void f(T,U) {} // (1) template <typename T> void f(T,T) {} // (2) template <> void f(int,int) {} // (3); specializes (2),not (1); why?
从理论上讲,(3)也可以是(1)的特化,但实验表明它不是.
解决方法
这是两个不同的模板,例如(2)不是(1)的专业化.好的,现在我们写专业时:
template <> void foo(int,int) {}
在推断出要专门化的模板时,编译器将识别两个候选者.然后,它必须选择哪个最合适.这种选择的过程称为“partial ordering of function templates”.选择报价:
When the same function template specialization matches more than one overloaded function template (this often results from template argument deduction),partial ordering of overloaded function templates is performed to select the best match.
让我们调用S匹配模板集.然后,对于S中的每对(f1,f2),编译器将通过在其类型(resp.非类型)参数上应用虚拟类型(resp.值)来变换f1.然后它尝试将它与f2匹配.然后它通过转换f2并尝试将其与f1匹配来执行相同的过程.最后,在完成每一对之后,编译器可以确定哪个候选模板是最专业的.如果未能这样做,则编译失败.
在我们的例子中,我们有两个匹配的模板,因此我们应用上述过程:
>转换(1)应用于(2):假设foo,T = T1且U = T2.它试图与(2)匹配:扣除失败
>转换(2)应用于(1):foo(T1,T1),当应用于(1)时,它解析为T = T1且U = T1.
从这个过程,编译器推断出(2)比(1)更专业,你的专业化为(2).当编译器关注特定调用时,在重载解析期间应用相同的过程.
所有这些程序的一个例子如下(摘自@ Yakk的评论):
template <typename T,U) { std::cout << "f(1)\n"; } // f(1) template <typename T> void f(T,T) { std::cout << "f(2)\n"; } // f(2) template <> void f(int,int) { std::cout << "f(3)\n"; } // f(3); specializes f(2),not f(1); why? // Now the same specialization but without any template overload... template <typename T,typename U> void g(T,U) { std::cout << "g(1)\n"; } // g(1) template <> void g(int,int) { std::cout << "g(3)\n"; } // g(3); No ambiguity,specializes g(1)
接下来,让我们执行几个调用:
f(1,1); // Prints f(3) f<int>(1,1); // Prints f(3) f<int,int>(1,1); // Prints f(1) g(1,1); // Prints g(3) g<int,1); // Prints g(3)
所有这些都可以在行动here – copied from @Yakk’s comment中看到.