让我们重点关注通用模板 (1) 和 (2) 的声明。
这是两个不同的模板,例如(2) 不是 (1) 的特化。好的,现在当我们编写专业化时:
template <>
void foo(int, int) {}
在推断要专门化的模板时,编译器将识别两个候选模板。然后,它必须选择哪个是best fit。这种选择的过程称为“函数模板的部分排序” http://en.cppreference.com/w/cpp/language/function_template。所选报价:
当相同的函数模板特化匹配多个重载函数模板时(这通常是由模板参数推导引起的),将执行重载函数模板的部分排序以选择最佳匹配。
我们打电话吧S匹配模板集。然后,对于每一对(f1, f2) in S,编译器将转换f1通过在其类型(或非类型)参数上应用虚拟类型(或值)。然后它尝试将其与f2。然后它通过转换执行相同的过程f2并尝试将其与f1。最后,在检查每一对之后,编译器可以确定哪个模板候选是最专业的。如果不这样做,编译就会失败。
在我们的例子中,我们有两个匹配的模板,因此我们应用上述过程:
- 变换后的 (1) 应用于 (2):用 T = T1 且 U=T2 表示 foo。它尝试与(2)匹配:推演失败
- 转换后的 (2) 应用于 (1):foo(T1, T1),当应用于 (1) 时,它解析为 T = T1 且 U = T1。
从这个过程中,编译器推断出 (2) 比 (1) 更专业,并且您的专业化适合 (2)。当编译器专注于特定调用时,在重载决策期间应用相同的过程。
以下是说明所有此过程的示例(摘自@Yakk 的评论):
template <typename T, typename U>
void f(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)
f(0.1, 0.2); // Prints f(2)
g(1, 1); // Prints g(3)
g<int, int>(1, 1); // Prints g(3)
这一切都可以在行动中看到这里 - 复制自@Yakk 的评论 http://coliru.stacked-crooked.com/a/ba4835ef93c33db1.