错误的模板函数推导

问题描述

以下程序中发生了意外的函数推导。 -

案例一 -

template <typename T,typename>
void foo(T x,int) {
    cout << "In int foo\n";
}

template <typename T>
void foo(T x,char) {
    cout << "In char foo\n";
}

int main() {
    string s = "Hello World";
    foo(s,(int) 1);
}

输出

In char foo

案例二 -

template <typename T>
void foo(T x,(int) 1);
}

输出

In int foo

对于案例 II,我只是从第一个函数删除了最后一个模板参数 typename。有人可以解释一下这里发生了什么吗?

解决方法

在这个函数中,

template <typename T,typename>
void foo(T x,int) {
    cout << "In int foo\n";
}

你告诉编译器,

  1. 有 2 个模板参数。
  2. 退货无效。
  3. 采用两个参数,一个来自 T 类型,另一个是 int
  4. 然后是函数体。

编译 foo(s,(int) 1); 时,编译器知道 T 的类型是由参数给出的,第二个参数也给出。但是第二个模板参数是未知的。因此,编译器会尝试找到另一个最合适的函数,在本例中为另一个 foo 函数。

这次编译器再次测试它并通过了,因为int可以隐式转换为char。这就是为什么它在第一种情况下输出 In char foo

第二种情况,由于没有未知类型,最合适的就是第一个函数void foo(T x,int)。这是因为第二个参数类型是 int 而函数的第二个参数类型也是 int

要解决第一种情况下的问题,您可以为模板提供默认类型参数。这样它就知道第二个类型参数,因此可以正常工作。

template <typename T,typename = void>
void foo(T x,int) {
    cout << "In int foo\n";
}
,

有点等价于这个,对结果感到惊讶:

void foo(int a,int);
void foo(float b);

int main () {
    foo((int) 1); // calls the float version
}

为什么叫浮动版?因为您缺少第二个 int 参数!如果你只发送一个参数,你就不能调用那个版本

只需删除第二个 int 参数使其可调用!

与您的代码相同。您的函数 foo 需要两个模板参数,只能推导出一个,并且您没有将它们发送给编译器。删除一个将使其工作。您还可以设置默认值:

template <typename T,int) {
    cout << "In int foo\n";
}

编译器将能够选择该参数,因为它具有您未提供的第二个模板参数的默认值。