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

z3d*_*3dd 1 c++ templates language-lawyer

以下代码传递断言:

int foo() { return 1; }

template<typename T>
int foo() { return 2; }

int main() {
  assert( 1 == foo() );
  assert( 2 == foo<int>() );
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

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

[...]鉴于这些定义,如果对于所有参数,可行函数F1被定义为比另一个可行函数更好的函数,不是比转换序列更差,然后[...] 是非模板函数,是一个功能模板专业化[...]F2iICSi(F1)ICSi(F2)F1F2

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

Pet*_*ker 5

你引用的文字比较密集; 你必须仔细阅读."如果对于所有论证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)
Run Code Online (Sandbox Code Playgroud)

在此示例中,f<int>是模板特化的名称.它不是一般命名的函数f,因此不需要考虑重载,就像调用一样g(3.14).

  • @z3dd 是的,它们是不同的: `foo&lt;int&gt;` 是模板实例化。所以它不能与非模板 `foo` 相同。您不能通过提供模板参数来引用非模板。所以没有任何歧义。 (2认同)