为什么在具有相同签名的模板化和非模板化函数之间进行选择时没有歧义?

Why no ambiguity when choosing between templated and non-templated functions with same signatures?

本文关键字:行选 之间 选择 歧义 函数 为什么      更新时间:2023-10-16

以下代码传递断言:

int foo() { return 1; }
template<typename T>
int foo() { return 2; }
int main() {
assert( 1 == foo() );
assert( 2 == foo<int>() );
return 0;
}

但据我了解,根据C++11标准第13.3.3/1段:

[...]给定这些定义,一个可行的函数F1被定义为比另一个可行的函数更好的函数F2如果对于所有参数iICSi(F1)不是比ICSi(F2)更糟糕的转换序列,然后[...]F1是非模板函数,F2是函数模板专用化 [...]

它不应该,因为签名最终是相同的。那么,为什么在调用foo<int>()时没有歧义呢?我错过了什么?

你引用的文本相当密集;你必须仔细阅读。"如果对于所有参数i,F1 比 F2 更好,ICSi(F1) 不是一个比 ICSi(F2) 更差的转换序列" -- 这里是正确的,因为两个转换序列是相同的,因此,任何一个都不比另一个差。所以现在你转到最后一部分:">然后F1 是一个非模板函数,F2 是一个函数模板专用化"。这是真的,所以F1比F2更好。将foo()foo<int>()分别替换为 F1 和 F2,规则说foo()foo<int>()更好匹配。

哎呀,我回答了错误的问题。正如评论所指出的,问题是,为什么明确调用foo<int>()不能解决foo()?答案是,foo<int>()是对显式模板实例化的调用,而不是对重载函数的调用。考虑:

template <class Ty>
void f(Ty) { }
void f(int);
void g(int);
f(3.14);      // calls f<double> (overloaded function call)
f(1);         // calls f(int) (overloaded function call)
f<int>(3.14); // calls f<int> (explicit call of template instantiation)
g(3.14);      // calls g(int)

在此示例中,f<int>是模板专用化的名称。它不是名为f的通用函数,所以没有重载需要考虑,就像调用g(3.14)一样。