错误的模板函数推导

Wrong template function deduction

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

案例一 -

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) {
    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 int foo

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

在这个函数中,

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

你告诉编译器,

  1. 有2个模板参数。
  2. return无效。
  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, typename = void>
void foo(T x, int) {
    cout << "In int foo\n";
}

编译器将能够select这个,因为它有一个你没有提供的第二个模板参数的默认值。