我有以下代码:
#include <iostream>
template <typename T>
void f (T) { std::cout << "f(T)" << std::endl; }
template <typename T>
void f (bool) { std::cout << "f(bool)" << std::endl; }
int main ( )
{
f(true); // #1 prints f(T)
f<bool>(true); // #2 prints f(bool)
}
#1
行调用f(T)
,而#2
行调用f(bool)
。
为什么会这样?选择重载模板函数的规则是什么?
更新
据我所知,在第一次调用时,编译器在尝试调用第二个函数时无法推断T
,因此选择第一个函数。
在第二个调用中,第二个函数被认为是更好的匹配gcc,而第一个函数是在VS2013下选择的。谁在这里做对了?顺便说一下,我仍然对这个过程的完整描述感兴趣。
答案 0 :(得分:14)
非专业化的功能模板也称为底层基础模板。基础模板可以是专用的。重载规则看看哪些在不同的情况下被调用,非常简单,至少在高级别:
非模板功能是一等公民。一个与参数类型以及任何函数模板匹配的普通旧的非模板函数将被选择在一个非常好的函数模板上。
如果没有一流的公民可供选择至少同样好,那么接下来就咨询二等公民的功能基础模板。选择哪个功能基础模板取决于哪个匹配最佳,并且是#34;最专业的&#34; (重要提示:根据一系列相当神秘的规则,使用&#34;专门的&#34;奇怪的是与模板专业化无关;它只是一个不幸的口语):
如果清楚的话,那就是最专业的&#34;功能库模板,使用它。如果该基本模板碰巧专门用于所使用的类型,则将使用特化,否则将使用使用正确类型实例化的基本模板。
否则(如你的情况)如果&#34;最专业的&#34;函数库模板,调用不明确,因为编译器无法确定哪个是更好的匹配。 程序员必须做一些事情才能使电话有资格并说明需要哪一个。
否则,如果没有可以匹配的功能基础模板,则调用很糟糕,程序员必须修复代码。
如果要自定义功能库模板并希望该自定义参与重载解析(或者,在完全匹配的情况下始终使用),请将其设置为普通旧函数,不是专业化。并且,如果您确实提供了重载,请避免提供专业化。
以上是 Herb Sutter的this帖子的摘录,在突出显示的项目符号中,您可以看到问题的来源
编辑
如果您尝试使用Visual Studio 2012上面的代码(不要这样做),那么
致命错误LNK1179:文件无效或损坏:重复COMDAT&#39; ?? $ f @ _N @@ YAX_N @ Z&#39;
,如here所述,是因为
你做了一些&#34;诡计&#34;这是无效的C ++,它传递了编译器,但你现在有一个无效的* .obj,它会扼杀链接器。
以下行是责备
f(true); // #1 prints f(T)
所以答案中解释的歧义没有得到保证决议
答案 1 :(得分:2)
实际上你想要的是模板专业化,在你的情况下,应该写成:
template<> // Without any typename in it!
void f (bool) { std::cout << "f(bool)" << std::endl; }
这在VS2012中按预期工作。