C++ 模板函数重载决议
Posted
技术标签:
【中文标题】C++ 模板函数重载决议【英文标题】:C++ template functions overload resolution 【发布时间】:2014-04-20 03:02:46 【问题描述】:我有以下代码:
#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 下选择的。谁在这里做正确的事?顺便说一句,我仍然对过程的完整描述感兴趣。
【问题讨论】:
不知道规则,但我看不出编译器如何在你的第二个模板中推断出T
,所以我看不出如果没有明确的参数如何选择它。 (但同样,我对模板细节一无所知。)
【参考方案1】:
未特化的函数模板也称为基础基础模板。基础模板可以是特化的。查看哪些在不同情况下被调用的重载规则非常简单,至少在高层次上是这样:
非模板函数是一等公民。与参数类型以及任何函数模板相匹配的普通旧非模板函数将被选择,而不是其他情况相同的函数模板。
如果没有至少一样好的一等公民可供选择,那么接下来咨询二等公民的功能基本模板。选择哪个函数基模板取决于哪个匹配最好并且是“最专业的”(重要说明:奇怪的是,“专业”的这种使用与模板专业化无关;这只是一种不幸的口语)根据一组公平神秘的规则:
如果很明显有一个“最专业”的函数基础模板,那么就会使用那个模板。如果该基本模板恰好专门用于正在使用的类型,则将使用该专门化,否则将使用使用正确类型实例化的基本模板。
否则(如您的情况)如果“最专业”的函数基本模板存在相同的情况,则调用不明确,因为编译器无法确定哪个更匹配. 程序员必须做一些事情来限定调用并说出需要哪个调用。
否则,如果没有可匹配的函数基模板,则调用错误,程序员将不得不修复代码。
如果您想自定义函数基模板并希望该自定义参与重载解析(或者,始终在完全匹配的情况下使用),请将其设为普通旧函数,不是专业。而且,如果您确实提供了重载,请避免同时提供特化。
以上内容摘自 the Herb Sutter 的 this 帖子,在突出显示的项目符号中,您可以看到问题的根源
编辑
如果您在 Visual Studio 2012 中尝试(不要这样做)上述代码,您会得到 p>
致命错误 LNK1179:无效或损坏的文件:重复 COMDAT '??$f@_N@@YAX_N@Z'
正如here 解释的那样,这是因为
你做了一些无效 C++ 的“诡计”,它通过了编译器,但你现在有一个无效的 *.obj,它阻塞了链接器。
下面这行是罪魁祸首
f(true); // #1 prints f(T)
所以答案中解释的歧义没有保证解决
【讨论】:
您可能想感谢 Herb Sutter 的摘录,参见。 gotw.ca/publications/mill17.htm. 那么,第二个调用是歧义?第一个电话是怎么回事? Herb 的解释我已经看了好几遍了,还是不明白。我认为这取决于“最专业”的含义。有人会认为 f(bool) 更专业,但显然不是,无论在什么意义上,这里使用了“专业”。我不明白的第二件事是 f(true) 和 f实际上你想要的是一个模板专业化,在你的情况下,应该这样写:
template<> // Without any typename in it!
void f (bool) std::cout << "f(bool)" << std::endl;
这在 VS2012 中按预期工作。
【讨论】:
以上是关于C++ 模板函数重载决议的主要内容,如果未能解决你的问题,请参考以下文章