c++模板函数的重载解析
C++ template functions overload resolution
我有以下代码:
#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下被选择。谁做的是对的?顺便说一下,我还是对整个过程的详细描述很感兴趣。
非特化函数模板也称为底层基模板。基模板可以专门化。重载规则用于查看在不同情况下调用哪些重载规则,非常简单,至少在高层是这样:
-
非模板函数是一等公民。与参数类型匹配的普通旧非模板函数以及任何函数模板都将被选择,而不是其他同样好的函数模板。
-
如果没有一级公民可供选择,那么作为二级公民的函数基模板将被下一步参考。选择哪个函数基模板取决于哪个匹配最好,并且是"最专门化的"(重要注意:奇怪的是,"专门化"的使用与模板专门化无关;这只是一个不幸的口语)根据一组相当晦涩的规则:
-
如果很明显有一个"最专门"的函数基模板,那么就使用这个模板。如果该基模板恰好是为所使用的类型专门化的,则将使用专门化,否则将使用用正确类型实例化的基模板。
-
Else(如您的情况)如果存在"最专门化"函数基模板的匹配,则调用是模糊的,因为编译器无法决定哪个是更好的匹配。程序员必须做一些事情来限定调用,并指出哪一个是需要的。
-
如果没有可以匹配的函数基模板,则调用是错误的,程序员将不得不修复代码。
-
如果您想自定义函数基模板并希望该自定义参与重载解析(或者,总是在精确匹配的情况下使用),请使其成为一个普通的旧函数,而不是专门化。而且,如果您确实提供了重载,请避免同时提供专门化。
以上摘自 Herb Sutter的文章,在突出显示的项目符号中,您可以看到问题的根源
编辑
如果你在Visual Studio 2012中尝试(不要这么做)上面的代码,你会得到
致命错误LNK1179:无效或损坏的文件:重复的COMDAT '??美元f@_N@@YAX_N@Z '
,正如这里所解释的,这是因为
你做了一些无效的c++"诡计",它通过了编译器,但你现在有一个无效的*。Obj,它会阻塞链接器。
和下面这行都是错的
f(true); // #1 prints f(T)
所以答案中的歧义不能保证解决
实际上您想要的是模板专门化,在您的情况下,应该这样写:
template<> // Without any typename in it!
void f (bool) { std::cout << "f(bool)" << std::endl; }
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 可以打印矢量和矢量中的矢量的非重载C++函数
- 错误 没有与参数列表匹配的重载函数"getline"实例
- 使用模板重载函数
- C++线程中,没有重载函数接受 X 参数
- std::vector 没有重载函数的实例与参数列表匹配
- C++重载函数,一个采用基类的参数,另一个采用派生类的参数
- 错误:无法解析对重载函数的引用;你的意思是调用它吗?
- 对重载函数find_first_not_of的不明确调用
- 如何从重载解析中删除重载函数?
- CUDA:重载函数"isnan"的多个实例
- C++派生类重载函数(带有 std::function 参数)不可见
- 避免在人为的重载函数调用中拼写出类型
- C++:如何为多个重载函数保留通用代码路径?
- 什么时候可以使用常量装饰调用我的重载函数?
- 尝试使用谓词函数会导致错误:"std::sort"未找到匹配的重载函数
- std::调用,未找到匹配的重载函数
- 为什么在传递长整型时调用具有两个双精度类型的参数的重载函数?
- 为什么使用不匹配的参数调用重载函数仍然有效
- 如何通过签名作为模板参数来解决重载函数?